Universite de Montreal

Un systeme de programmation Scheme

p our microcontroleur

par

Danny Dube

Departement dinformatique et

de recherche operationnelle

Faculte des arts et sciences

Memoire presente a la Faculte des etudes superieures

en vue de lobtention du grade de

Matre es sciences M Sc

en informatique

Avril

Danny Dube

Page didentication du jury

Universite de Montreal

Faculte des etudes superieures

Ce memoire intitule

Un systeme de programmation Scheme

p our microcontroleur

presente par

Danny Dube

a ete evalue par un jury comp ose des p ersonnes suivantes

Yoshua Bengio

president du jury

Francois Ma jor

Marc Feeley

directeur de matrise

Memoire accepte le er ao ut

Sommaire

Notre travail vise a etudier les dierents asp ects relies a un systeme de programmation

Scheme compact Le but principal consiste a montrer quon p eut faire une implantation suf

samment compacte p our p ouvoir fonctionner sur un microcontroleur Les buts secondaires

consistent a trouver ou developper un gestionnaire memoire automatique GC temps reel im

plantable de facon compacte ainsi que de choisir des techniques p ortables

Les dierents asp ects que nous etudions sont la representation des donnees principalement

en ce qui concerne le typage les symboles les continuations et les environnements lexicaux

plusieurs techniques de GC temps reel et la recherche dune technique originale le developpement

dun mo dele dexecution tres compact utilisant la compilation

A priori il ne semble pas evident datteindre lob jectif principal Plusieurs systemes Scheme

compacts existent deja et aucun de ceuxci ne p eut se plier aux contraintes severes imp osees par

un microcontroleur La contrainte ma jeure imp osee par un microcontroleur est la p etitesse de

lespace memoire

TABLE DES MATIERES

Table des matieres

Introduction

Ob jectifs

Motivation

Problematique

Methodologie

Description precise de lob jectif

Type de machine cible

Survol de Scheme

Scheme sur microcontroleur

Continuations

Denition

Acces aux continuations en Scheme

Exemple dutilisation des continuations

Impact sur linterprete

Traitement des app els terminaux

Denition dapp el terminal

Implantation correcte

Impact sur linterprete

Gestion memoire

TABLE DES MATIERES

Denition

Interet de la denition

Traitement derreurs

Question decacite

Representation des ob jets

Representation des types

Representation uniforme

Representation taggee

Les autres representations

Nos choix dimplantation

Les symboles

Contenant directement le nom

Numerotation des symboles

Les continuations

Pile

Fermetures

Structures de donnees ad hoc

Nos choix dimplantation

Les environnements

Listes dasso ciation

Listes

Blo cs de liaison chanes

Blo cs de liaison avec display

Representation plate

Nos choix dimplantation

Recherche dun GC adequat

TABLE DES MATIERES

Limp ortance deviter la fragmentation

Les dicultes liees aux GC temps reel

Lincoherence des donnees

Les mutations faites par lapplication

Les grands ob jets

Reglage de la vitesse du GC

Les dierentes appro ches

Regroup ement en zones ou en pages

GC a deux semiespaces

GC a un seul espace

La version blo quante de notre technique de GC

Disp osition du tas

Declenchement du GC

Description de lalgorithme

La technique temps reel

Les barrieres en lecture et en ecriture

Lalgorithme du GC

Synchronisation du GC avec lapplication

Trois ameliorations

Le calcul du ratio utilise par linterprete

Compilation vers du co deo ctets

Ap ercu du systeme

Le systeme entier

Le compilateur

Reduction des formes syntaxiques derivees

Les formes de base

TABLE DES MATIERES

Les reductions proprement dites

Transformation en arbres de syntaxe

Selection des fonctions de la librairie

References globales

La librairie

Extraction des fonctions requises

Traitement des constantes litterales

Decoupage des constantes

Co dage des constantes

Reconstruction des constantes

Lo calisation des variables

Valeur initiale des variables globales

Valeur initiale

Utilite des valeurs initiales

Co dage des valeurs initiales

Substitution des fonctions app elees

Pro duction du co deo ctets

Organisation globale du co deo ctets

Compilation des formes syntaxiques

Linearisation et resolution des references

La machine virtuelle et le co deo ctets

La premiere machine virtuelle

Les registres

Comp ortement general

Operandes courts et longs

Operande facultatif

TABLE DES MATIERES

Le jeu dinstructions

Compilation des dierentes formes

Constantes

References de variables

Aectations et denitions

Blo cs dexpressions

Conditions

Lambdaexpressions

App els de fonctions

Qualite de la compilation

La deuxieme machine virtuelle

Instructions specialisees

Fusion dinstructions

Diverses nouvelles instructions

Empilement automatique

Imp ortance de la denition des instructions

Letat actuel des travaux

Details dimplantation

Le compilateur

Linterprete

Mesures de taille et de p erformance

Comparaison de la taille des executables

Tests de p erformance

Ameliorations p ossibles

Conclusion

TABLE DES MATIERES

A Sources du systeme

A Sources du noyau

A noyauh

A noyauc

A Le chier de librairie

A Le compilateur vers du co deo ctets

A Exemple de compilation vers du co deo ctets

TABLE DES FIGURES

Table des gures

Description du taggage

Soustypage des ob jets regroupes sous le type Autres types alloues

Illustration du tas contenant la liste

Ob jet alloue immediatement parmi les ob jets deplaces durant le compactage

Pro duction dun executable p our microcontroleur a partir du programme progscm

Extraits du chier de librairie

Traitement ideal de la description des constantes

Implantation de la fonction de Fib onacci utilisee p our un test de p erformance

Taille de lexecutable de plusieurs interpretes

Tests de p erformance comparatifs

CHAPITRE INTRODUCTION

Chapitre

Introduction

De plus en plus dappareils utilisent des microcontroleurs p our regler leurs dierentes fonc

tions Il su de p enser a divers appareils electromenagerselectroniques ou a la rob otique Plus

souvent quautrement les microcontroleurs sont programmes en assembleur La programmation

p eut aussi se faire dans des langages plus evolues par exemple C ou un autre langage de cet

acabit Ces langages sont plus interessants puisque le pro cessus de programmation y est plus

rapide et plus able

Notre recherche consiste a montrer quun langage aussi evolue que Scheme p eut aussi etre

utilise p our la programmation de ces microcontroleurs

Ob jectifs

Ce travail consiste a montrer la p ossibilite de realiser une implantation dun systeme de

programmation Scheme p our microcontroleur Nous ne cherchons pas necessairement a realiser

un interprete capable dinteragir avec un usager On p eut donc eectuer une compilation des

programmes an de generer limage memoire qui p ourra etre transferee sur le microcontroleur

Un ob jectif secondaire consiste a doter le systeme Scheme dun GC Garbage Collector

temps reel En eet un programme Scheme consomme de la memoire mais ne la retourne jamais

explicitement Il faut donc inclure un systeme de recuperation automatique de la memoire

Les GC blo quants ont la facheuse tendance a provoquer des pauses momentanees dans le l

dexecution du programme Ce seul defaut p eut rendre un systeme de programmation Scheme

b eaucoup moins attrayant p our une application Un GC temps reel evite le probleme des pauses

Enn les techniques que nous developpons ou p our lesquelles nous optons doivent sappliquer

dans un contexte generalNous ne sommes pas interessespar des techniques qui sont dependantes

dun microcontroleur particulier ou dune caracteristique technique du contexte dutilisation

CHAPITRE INTRODUCTION

Motivation

Il y a plusieurs raisons de sinteresser a un systeme Scheme compact Pour autant que nous

sachions il na a pas de telle implantation ou du moins aucune qui ne soit destinee a fonc

tionner dans un environnement aussi restrictif quun microcontroleur Plusieurs implantations

sont relativement compactes comme Scm IntScm Sio d IntSiod et surtout Minischeme

IntMini Mais elles sont soit trop volumineuses p our un microcontroleur soit incompletes

La section donne des mesures concretes Enn il existe une machine concue expressement

p our le langage Lisp Une implantation materielle nest toutefois pas tres generale et est p eu

economique

Comme nous le mentionnons brievement au debut de lintroduction il existe deja des sys

temes compacts de programmation p our dierents langages Par exemple il y a des interpretes

Basic et Forth contenus sur une memoire extremement reduite et qui p euvent interagir avec

lusager Il y a aussi des compilateurs p our dierents langages qui p euvent generer du co de natif

p our plusieurs microcontroleurs Il est manifestement interessant de p ouvoir programmer les

microcontroleurs autrement quen assembleur

Bien s ur le co de natif pro duit par un compilateur nest pas toujours daussi b onne qualite

que celui ecrit par un programmeur assembleur chevronne De meme un programme qui est

interprete ne fonctionne pas aussi vite que sil etait traduit en co de natif Toutefois le dilemme

entre lutilisation doutils evolues et la realisation manuelle ne se p ose pas uniquement dans

la programmation des microcontroleurs Nous considerons que la programmation dun micro

controleur en Scheme reste un probleme interessant malgre que lon p erde de la p erformance

par rapp ort a la programmation en assembleur

Un attrait de Scheme vient du fait que cest un langage plus evolue que ceux utilises couram

ment Des langages comme Basic Pascal et C sont grosso modo du meme niveau dabstraction

De la meme facon quil est plus facile de programmer dans ces langages quen assembleur il

est encore plus facile de programmer en Scheme Lavantage de Scheme sur ces langages vient

surtout du nombre restreint de concepts donc de sa simplicite de la gestion automatique de

la memoire et du traitement des erreurs

Premierement le langage Scheme comp orte p eu de concepts mais ceuxci sont susamment

puissants p our p ermettre dexprimer aisement la plupart des programmes que lon fait en C

par exemple Une faiblesse de Scheme par rapp ort a C toutefois est la distance creee entre le

programme et les operations de tres bas niveau Par exemple en Scheme les acces a des adresses

particulieres en memoire ne sont p ossibles que par lintermediaire de fonctions specialisees

Deuxiemement un systeme Scheme fournit un disp ositif automatique de recuperation de

la memoire La gestion de la memoire est lun des gros problemes lors du developpement des

applications dans les langages de plus bas niveau

Troisiemement lorsquune erreur se pro duit en Scheme elle est detectee et rep ortee en termes

de concepts de Scheme Il ny a pas doperations illicites qui sont acceptees silencieusement ou

CHAPITRE INTRODUCTION

detectee par le systeme dexploitation Cette qualite rend le developpement de programmes plus

facile

Linteret des langages plus evolues est clair Plus le langage est evolue plus il est facile de

programmer des taches complexes Par exemple en rob otique le travail a eectuer est souvent

complexe

Scheme est donc interessant p our le developpement de programmes En outre il est su

samment simple p our quil soit envisageable de limplanter de facon compacte Les concepts

environnements lexicaux fermetures recursion de queue en espace constant continuations

sont p eu nombreux et ne semblent pas a priori demander une utilisation intensive de memoire

Ensuite la librairie standard comp orte un nombre reduit de fonctions Ce sont ces raisons qui

nous p oussent a croire quil est p ossible darriver a faire un systeme Scheme compact

Enn bien que notre etude vise limplantation sur microcontroleur le developpement de

techniques p ortables rend ces dernieres utilisables sous dautres contextes Dans les situations

o u leconomie despace prime sur lecacite nos resultats p euvent saverer utiles

Problematique

Bien que la realisation dun systeme Scheme compact semble p ossible on ne p eut en etre

s ur a priori Premierement b eaucoup de recherches ont deja ete faites sur les dierents asp ects

dun systeme Scheme Mais ces recherches p ortent principalement sur la recherche decacite en

temps Il faut donc comparer les techniques existantes et eventuellement en chercher de nouvelles

p our avoir les techniques les plus economes en espace

Deuxiemement comme nous le disons plus haut il ny a pas a notre connaissance dimplan

tation assez compacte p our etre utilisee sur un microcontroleur Il nest p eutetre pas p ossible

de realiser une telle implantation

Methodologie

Nous avons developpe plusieurs versions dun systeme Scheme Les premieres sont des inter

pretes interactifs Dans ces versions nous testons plusieurs techniques de GC et des representa

tions p our les ob jets Les dernieres versions sont constituees dun compilateur vers du co deo ctets

bytecode et dun interprete de co deo ctets Notre implantation du compilateur est en Scheme

et celle du noyau en C Le compilateur sert a traduire un programme source en un chier de

co deo ctets destine a etre lie avec linterprete Nous y avons adopte une nouvelle representation

des environnements et plusieurs techniques p our ameliorer de nombreux p oints secondaires

Les chapitres du memoire ne suivent pas lordre chronologique du developpement Ils re

group ent plutot la discussion par asp ects Le pro chain chapitre sert a preciser les ob jectifs tout

CHAPITRE INTRODUCTION

en introduisant les notions qui sont les plus utiles p our la comprehension de ce travail Les cha

pitres suivants traitent de la representation des ob jets du GC du compilateur et de linterprete

de co deo ctets Quelques resultats experimentaux sont presentes avant la conclusion

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

Chapitre

Description precise de lob jectif

Dans ce chapitre nous decrivons plus en detail le but que nous voulons atteindre dans

notre travail Premierement nous precisons les caracteristiques du type de machine qui nous

interesse Deuxiemement nous faisons un survol du langage Scheme en insistant sur les p oints

qui sont particulierement imp ortants du p oint de vue de limplanteur Enn nous expliquons

plus formellement ce que nous entendons par GC temps reel

Type de machine cible

Le type de machine qui nous interesse p our ce travail est le microcontroleur Il sagit dun

ordinateur dusage general et de faible capacite tant en memoire quen puissance de calcul Les

microcontroleurs sont typiquement tres b on marche et p euvent etre integres a toutes sortes

dappareils p our controler leur fonctionnement

Lorsque lon realise une application p our un tel microcontroleur on ecrit un programme

p our decrire la tache a eectuer Typiquement la programmation se fait en assembleur et le

programme est assemble grace a un logiciel fourni par le fabriquant Ensuite le programme

compile est inscrit dans la memoire morte ROM et repro duit a grande echelle Lors de la

fabrication dun appareil le microcontroleur et le mo dule ROM contenant le programme ade

quat y sont inclus et connectes Ainsi un microcontroleur tout usage p eut etre utilise dans une

multitude de taches dierentes simplement en changeant sa programmation

Le microcontroleur que nous avons adopte p our ce travail est le HC de Motorola Cest

un microcontroleur tres repandu qui represente bien les microcontroleurs qui existent sur le

marche Il p ossede un pro cesseur bits qui p eut eectuer certaines operations sur bits Les

adresses sont co dees sur bits et lespace dadressage est donc limite a Ko ctets Il disp ose

dun tres p etit nombre de registres dont un seul est dusage general Lhorloge reglant

le deroulement des cycles de la machine fonctionne a MHz En moyenne les instructions

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

requierent environ cycles p our etre executees Ce genre de microcontroleurs nest certes pas

fait p our eectuer du calcul intensif On ne p eut raisonnablement esperer que les programmes

aient une execution tres rapide sur une telle machine

La limite de Ko ctets sur lespace dadressage est la contrainte principale imp osee a une

implantation de Scheme et elle est liee a lutilisation de la plupart des microcontroleurs Toutes

les parties dun interprete Scheme doivent p ouvoir etre contenues dans cet espace noyau de

linterprete interprete de co deo ctets librairie du langage programme a executer et donnees

creees a lexecution

Survol de Scheme

Le langage Scheme est un des derives de Lisp Il sagit donc dun langage fonctionnel impur

a syntaxe parenthesee qui est bien adapte p our le calcul symbolique Contrairement a certains

dialectes de Lisp il utilise la p ortee lexicale Le passage des parametres se fait toujours par

valeur Il est type dynamiquement ou faiblement type Meme sil est souvent utilise comme un

langage fonctionnel Scheme p ermet les eets de b ords sur les variables et dans les structures

de donnees La recuperation de lespace memoire est faite automatiquement Cest un langage

concu avec une philosophie minimaliste

Scheme p ossede les types suivants les b o oleens les nombres les caracteres les paires les

vecteurs les chanes de caracteres les symboles et les fonctions

Les paires sont les ob jets a deux champs qui sont utilises dans tous les dialectes de Lisp

p our constituer les listes Les vecteurs sont similaires aux tableaux a une dimension que lon

retrouve dans les langages plus traditionnels Les listes et les vecteurs ne sont pas resteints a

ne contenir que des ob jets dun seul type Une implantation normale p ermet deectuer des

acces aleatoires dans un vecteur b eaucoup plus rapidement que dans une liste

Les symboles sont des ob jets qui sont entierement decrits par leur nom Deux symboles

nommes exactement de la meme facon sont en fait le meme symbole Il est p ossible dobtenir

le nom dun symbole sous la forme dune chane de caracteres et de faire loperation inverse a

partir dune chane

Les fonctions sont reconnues comme ob jets de premiere classe et jouent un role ma jeur en

Scheme Par ob jets de premiere classe on signie que les fonctions p euvent etre creees sto ckees

dans des structures de donnees passees en parametre et retournees par dautres fonctions La

ma jorite des fonctions manipulees dans un programme sont soit des fonctions primitives de la

librairie soit des fermetures Les fermetures sont creees par les lambdaexpressions comme en

lambdacalcul Elles ne sont toutefois pas limitees a un seul parametre Comme en lambdacalcul

le fait dexecuter une lambdaexpression cree une fermeture cestadire que lenvironnement

lexical des variables en p ortee est conserve avec le corps de la lambdaexpression Enn

certaines fonctions sont des continuations qui ont ete reiees Nous discutons des continuations

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

dans une section a part

La librairie de Scheme est principalement constituee des fonctions de manipulation des ob jets

des dierents types On y retrouve aussi quelques fonctions dordre superieur dusage courant

La librairie est relativement reduite et cest une des raisons qui laisse croire que Scheme p eut

etre implante de facon compacte

Scheme comprend quelques formes syntaxiques Quelquesunes ne sont pas remplacables

comme les lambdaexpressions et les aectations mais la plupart sont du sucre syntaxique

Le nombre restreint de formes de base est une autre contribution a la simplicite du langage

Enn le standard R RS requiert que les app els en p osition terminale seectuent sans

consommation despace Nous discutons de ce p oint particulier dans une section separee

Scheme sur microcontroleur

Certains asp ects de Scheme p erdent leur interet ou leur sens lorsque lon sinteresse a la

programmation des microcontroleurs

Premierement nous ne desirons pas implanter toute la tour des nombres Les rationnels et

les complexes ne sont pas dusage courant et dailleurs ils manquent a plusieurs implantations de

Scheme Par contre les nombres reels en p oint ottant sont dusage courant en programmation

Mais pas necessairement en programmation de microcontroleurs Un microcontroleur typique

comme le HC ne traite pas les nombres en p oint ottant Nous preferons eviter da jouter

des librairies p our simuler des nombres en p oint ottant Il en va de meme p our les entiers de

taille illimitee Notre systeme Scheme ne comp orte donc que des entiers de taille b ornee

Deuxiemement les fonctions dentreessorties textuelles p erdent leur interet dans le contexte

dun microcontroleur Linterprete Scheme nest pas destine a fonctionner interactivement en

core moins a etre branche a un serveur de disques En fonction de lutilisation prevue du micro

controleur les b esoins p our des fonctions dentreessorties p euvent changer Nous ne p ouvons

pas raisonnablement xer un mo dele particulier de communication avec lexterieur donc nous

ne nous sommes pas attardes sur les questions dentreessorties

Continuations

La presence des continuations comme ob jets de premiere classe est un trait de Scheme qui se

retrouve dans p eu dautres langages Meme si une grande partie des programmes Scheme nuti

lisent pas explicitement les continuations et quune seule fonction de la librairie les concernent

les continuations nen demeurent pas moins un outil puissant En outre elles imp osent b eaucoup

de contraintes a limplanteur dun systeme Scheme

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

Les continuations sont specialement utiles sur un microcontroleur En eet les micro

controleurs sont souvent utilises p our traiter plusieurs signaux et controler de nombreux dis

p ositifs simultanement Or la programmation concurrente est tres utile p our eectuer un tel

traitement On voit justement a la section comment les continuations p ermettent de faire

de la programmation concurrente Une telle application constitue selon nous une justication

susante p our p ermettre lexistence des continuations comme ob jets de premiere classe dans

notre interprete

Cette section sert a illustrer ce que sont les continuations et a montrer quels impacts elles

ont sur la structure dun interprete Premierement une denition des continuations est donnee

Deuxiemement la fonction callcc est introduite Troisiemement lutilite des continuations

est illustree par un exemple Enn nous discutons brievement de limpact des continuations sur

larchitecture dun interprete

Denition

Intuitivement une continuation est un calcul susp endu qui attend un resultat p our se p our

suivre La continuation courante est le calcul qui reste a faire lorsque le calcul courant se

termine Une continuation attend apres le resultat du calcul courant

Exemple

Prenons par exemple cette expression

set x car p

Levaluation de cette expression se decompose de la facon suivante sans decomposer lapp el

app el de la fonction car sur la paire contenue dans p aectation du resultat a la variable x Avant

de p ouvoir eectuer laectation a la variable x il est imperatif de connatre le resultat de lapp el

Laectation est le calcul a eectuer une fois que lapp el a rendu son resultat Laectation est

donc la continuation de lapp el

Si on considere que lexpression fait partie dun programme laectation ellememe a une

continuation Cest lexecution du reste du programme Dans ce cas la continuation de lapp el

est laectation suivie de lexecution du reste du programme

Conversion CPS

Un programme est normalement ecrit en style direct cestadire que les expressions ont

une valeur de retour Valeur de retour qui p eut etre passee en argument liee a une variable

Mais par conversion CPS on p eut transformer un programme ecrit en style direct en un

programme ecrit en style de passage par continuations Continuation Passing Style En style

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

CPS les expressions nont pas de valeur de retour elle ne retournent pas Elles passent plutot le

resultat de leur evaluation a leur continuation La continuation courante est toujours accessible

car elle est passee explicitement en parametre

En style CPS on represente les continuations par des fonctions a un parametre Toutes les

fonctions de la librairie et les lambdaexpressions prennent un parametre supplementaire qui est

la continuation Regardons notre exemple une fois converti en style CPS

lambda k

car p lambda result

set x result

k t

Notre exemple nest plus une expression prete a retourner une valeur le resultat indeni du

set disons t mais plutot une fonction qui recoit une continuation k

La premiere chose qui est faite dans cette fonction est deectuer lapp el La fonction car

prend maintenant deux parametres une paire et une continuation Une fois que le premier champ

de la paire est connu il est passe en parametre a la continuation celle recue par car

Cette continuation represente b el et bien le reste du calcul Elle consiste a aecter le resultat

a x et ensuite a p oursuivre lexecution du reste du programme Ceci est fait en passant le resultat

de lexpression set a la continuation k

Il est p ossible de convertir tout un programme en style CPS grace a des regles de transfor

mation systematiques Ce nest toutefois pas notre but de presenter une telle technique ici La

transformation qui precede vise seulement a illustrer la nature des continuations

Acces aux continuations en Scheme

Comme nous le disons plus haut un programme Scheme ne travaille habituellement pas

avec les continuations directement De toute maniere il est toujours p ossible de realiser un

programme sans utiliser les continuations Mais lacces aux continuations p ermet de simplier

grandement la programmation de certaines taches

Lacces aux continuations se fait grace a la fonction callwithcurrentcontinuation La

plupart des implantations lui donnent aussi le nom de callcc Cette fonction p ermet de reier

la continuation courante a un p oint donne du programme Il est imp ortant dutiliser le terme

reier car un interprete ne cree pas necessairement toutes les continuations qui entrent en jeu

conceptuellement

La fonction callcc recoit en parametre une fonction a un argument Elle linvoque en lui

passant en parametre sa propre continuation La continuation en question est reiee sous la

forme dune continuation semblable a celles que lon fait apparatre lors dune conversion CPS

Il sagit dune veritable fonction a un parametre Toutefois linvocation de la continuation na

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

pas le meme eet que linvocation dune fonction ordinaire Linvocation dune continuation ne

retourne jamais

callcc lambda k

if test

begin k f

Dans lexemple cihaut supp osons que levaluation se fasse de gauche a droite la reference

a le pro duit lapp el a callcc et enn la somme Dans ce cas la continuation de lapp el a

callcc consiste a eectuer la somme du resultat du pro duit et du resultat de lapp el a callcc

Loperation qui eectue la somme est precisement la continuation qui est passee a la fonction

via son parametre k De plus elle constitue la continuation courante durant lexecution du corps

de la fonction Donc que lexecution du corps se termine normalement ou quelle se termine par

une invocation explicite de la continuation recue dans k leet est le meme La somme seectue

sur ce nouveau resultat et sur celui du pro duit Dans le premier cas le resultat est arrive a la

continuation de maniere implicite grace a un retour de valeur Dans le deuxieme le resultat est

transmis explicitement a la continuation par linvocation de celleci Dans notre exemple lapp el

a callcc retourne quel que soit le resultat de la fonction test

Exemple dutilisation des continuations

Un exemple classique et simple a comprendre est la creation de fonctions dechappement

nonlo cal Cest une des applications les plus courantes des continuations Le fait de p ouvoir

abandonner un calcul lorsque necessaire p ermet de simplier grandement la programmation de

certaines applications

De nombreux langages fournissent un moyen deectuer des sorties nonlo cales Cet exemple

ne p ermet donc pas dillustrer le p otentiel des continuations Nous preferons presenter un

exemple de programmation concurrente

Il est imp ortant de bien savoir ce nous avons en tete lorsque nous parlons dexecution concur

rente Il ne sagit pas de parallelisme Lexecution du programme se fait sur un seul pro cesseur

et il ny a pas deux calculs faits en meme temps Il sagit davoir plusieurs ls dexecution dans le

programme A tout moment un de ces ls dexecution a le controle et eectue du travail Lorsque

cest juge approprie le l courant laisse temp orairement le controle aux autres ls dexecution

Il le retrouve par la suite

Ce type dexecution concurrente p eut etre programme en Scheme a laide des continuations

Le programmeur na qua inserer dans son programme des app els reguliers a une fonction de

changement de l dexecution De plus il p eut faire separer un l dexecution en deux ls

distincts et il p eut faire terminer un l dexecution

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

Nous presentons une implantation dexecution concurrente Les noms switch

fork et terminate sont ceux des trois fonctions decrites dans le paragraphe precedent dans

lordre Ces trois fonctions ne prennent pas dargument Seule la fonction fork retourne un

resultat signicatif qui est un b o oleen et qui p ermet au programme de distinguer les deux ls

dexecution generes Voici donc limplantation de ces fonctions

define threadhead cons f

define threadtail threadhead

define addthread

lambda thread

setcar threadtail thread

setcdr threadtail cons f

set threadtail cdr threadtail

define extractthread

lambda

if eq threadhead threadtail

begin display Erreur newline

let thread car threadhead

set threadhead cdr threadhead

thread

define switch

lambda

callcc lambda thread

addthread thread

extractthread f

define fork

lambda

callcc lambda thread

addthread thread

t

define terminate

lambda

extractthread f

Le co de demande quelques explications La liste des ls dexecution est une le dattente et

les deux premieres fonctions servent a a jouter a la n de et a extraire du debut de la le Il est

a noter que le l en cours dexecution ne se trouve pas dans la le dattente Ainsi la le est

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

vide sil ny a quun l dexecution

Comme nous le disons plus haut la fonction switch sert a passer le controle aux autres ls

dexecution Elle capture la continuation courante la sauve dans la le extrait une continuation

et p oursuit lexecution avec cette derniere On p eut imaginer que chaque continuation represente

letat du calcul dun l dexecution blo que

Lorsquun l dexecution tombe sur une expression switch son etat est sauve sous la

forme dune continuation dans la le dattente Eventuellement cette continuation est extraite

de la le et est invoquee Ceci a p our eet de ressortir de lapp el a switch Entre le moment

o u le l dexecution a app ele la fonction switch et celui o u lapp el se termine plusieurs ls

dexecution se sont p otentiellement succedes Sil ny a pas dautres ls dexecution toutefois

lapp el a switch se termine aussitot car la continuation qui vient tout juste detre sto ckee est

extraite immediatement

La fonction fork est construite sensiblement de la meme facon Mais celleci sert a dupliquer

un l dexecution Lorsquelle est invoquee elle capture la continuation et la sauve dans la le

dattente mais elle renvoit immediatement le controle a lapp elant Un app el a fork ressort donc

presque aussitot Toutefois letat du calcul a ete sauve au cours de lapp el Celuici constitue

donc la copie du l dexecution qui se p oursuit Ainsi un app el a fork retourne deux fois

Il est imp ortant de constater que la fonction fork retourne correctement les valeurs t et

f servant a dierencier les deux ls Nous p ouvons voir que le l original celui qui est

retabli aussitot apres lapp el a fork continue avec le resultat t Lautre l quant a lui sera

necessairement retabli par la fonction switch ou terminate donc il continuera avec le resultat

f Il est imp ortant de ne pas confondre les choses ici Ce deuxieme l meme sil sera retabli

par switch ou terminate est decrit par une continuation qui a ete capturee lors dun app el a

fork et p oursuivra donc son execution immediatement apres le site dapp el a fork

Finalement il reste a decrire la fonction terminate Celleci sert a faire disparatre un l

dexecution chose qui ne p eut etre faite avec les fonctions switch et fork Un app el a terminate

ne fait quextraire une continuation et lui passer le controle La continuation courante cesta

dire letat du calcul du l nest pas sauvee Un app el a la fonction terminate ne ressort donc

pas Il y a un cas special avec cette fonction et cest le cas o u le programme essaie de terminer

son unique l dexecution Ce cas est detecte dans la fonction dextraction de la le dattente

Dans lexemple nous ne faisons quecrire un message lorsque cela se pro duit

Ces fonctions que nous presentons sont reduites a leur plus simple expression Le program

meur dune application p ourrait vouloir plus de facilites rattachees a la gestion des ls dexecu

tion Par exemple donner des numeros distincts a tous les ls laisser un l dormir jusqua ce

quun signal indique de le remettre dans la le dattente etc Toutefois nous voulons montrer

la p ossibilite de faire de lexecution concurrente le plus simplement p ossible

Il est p ossible de batir une application qui gere de multiples ls dexecution sans laide des

continuations explicites Mais cette tache est terriblement dicile surtout lorsquon p ermet des

programmes recursifs

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

Impact sur linterprete

Connaissant les eets des continuations il est clair quelles imp osent des contraintes assez

fortes sur un interprete Une pile dexecution contigue comme on en retrouve dans les langages

plus conventionnels comme le C ne sut pas a realiser les continuations de Scheme En eet

en C lorsquun calcul sest termine on ne p eut y revenir Les informations concernant le calcul

ont ete depilees ou ecrasees et il ny a pas de moyen p ortables de prevenir cela Le mecanisme

dapp el de C ne p eut donc pas simuler le mecanisme dapp el de Scheme

Malgre les contraintes quimp osent necessairement les continuations sur larchitecture dun

interprete nous tenons tout de meme a les inclure dans notre systeme

Traitement des app els terminaux

Une caracteristique de Scheme est le traitement des app els terminaux Les implantations de

Scheme sont tenues de les implanter de facon appropriee ceci an de p ermettre au programmeur

Scheme dexprimer des iterations a laide de fonctions recursives terminales et dassurer que le

traitement se fasse sans consommation despace

An dillustrer ce que ceci signie nous presentons tout dab ord une denition dapp el termi

nal ensuite nous montrons la facon correcte de limplanter et enn nous discutons brievement

de limpact de cette contrainte sur une implantation de Scheme

Denition dapp el terminal

Toutes les expressions dun programme sont soit en p osition terminale soit en p osition non

terminale Intuitivement une expression est en p osition terminale si elle est le dernier calcul a

eectuer dans une fonction En particulier un app el est terminal sil est le dernier calcul a faire

dans le corps dune fonction

Prenons par exemple lapp el x y dans lexpression suivante

define countedsum

lambda x y

set sumcounter sumcounter

x y

Lapp el x y est le dernier calcul a eectuer dans le corps de la fonction et est donc en

p osition terminale

Toutefois dans lexpression set z x y le meme app el ne p eut etre en p osition

terminale car il reste laectation a eectuer Lapp el nest donc pas terminal quelle que soit la

p osition de lexpression set qui lenglob e

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

On p eut donner p our chaque forme syntaxique primitive les sousexpressions qui sont en p osi

tion terminale si et seulement si la forme ellememe lest Lexception est la lambdaexpression la

derniere expression de son corps est en p osition terminale dans tous les cas Les sousexpressions

qui nous interessent sont en gras

Les references de variables et les constantes litterales ne comp ortent pas de sousexpres

sions

App el de fonction hE i hE i hE i Aucune des sousexpressions dans lapp el nest le

n

dernier calcul a eectuer Meme apres levaluation du dernier argument il reste a invoquer

la fonction sur ses arguments

Lambdaexpression lambda hformelsi hE i hE i hE i La derniere expression du

n n

corps est le dernier calcul a eectuer et est toujours en p osition terminale

Expression conditionnelle if hE i hE i ou if hE i hE i hE i Le test nest jamais

le dernier calcul a eectuer dans une condition Le resultat est repris et determine quelle

branche sera executee La branche choisie est toutefois le dernier calcul a eectuer dans la

condition

Aectation et denition set hvariablei hEi et define hvariablei hEi La sous

expression presente dans les aectations et les denitions nest jamais en p osition terminale

a cause du fait que son resultat doit etre place dans une variable avant que lexpression

complete ne retourne son resultat

Nous ne tenons pas a enumerer chacune des formes syntaxiques derivees qui existent en

Scheme et decrire lesquelles de leurs sousexpressions sont en p osition terminale Le standard

decrit les transformations source a source qui p ermettent de ramener les formes derivees en des

formes primitives Une fois la forme reduite il sut de suivre les regles que nous avons donnees

p our trouver les expressions en p osition terminale

Implantation correcte

Les continuations p ermettent de comprendre rapidement ce qui doit etre fait dans une im

plantation correcte Pour ce prenons lexemple suivant

define writeanddecode

lambda n

write n

n

Le corps de la fonction comp orte deux app els Le premier nest pas en p osition terminale et le

second lest Voici une facon de convertir la fonction en style CPS

define writeanddecode

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

lambda n k

write n lambda result

n lambda result

k result

Si lon observe attentivement lexemple converti on remarque quil est inutile de creer une

nouvelle continuation p our le deuxieme app el En eet elle ne fait quintercepter le resultat de

la soustraction avant de le passer a la continuation k Si on avait plutot converti la fonction de

la facon suivante

define writeanddecode

lambda n k

write n lambda result

n k

elle aurait le meme comp ortement sauf quelle ne creerait pas de continuation inutilement

La deuxieme conversion represente en fait la facon correcte dimplanter lapp el terminal

Comme lapp el terminal est le dernier calcul de la fonction cest lui qui doit se charger de

retourner le resultat le passer a k Cest la fonction qui se charge de retourner le resultat

a la place de writeanddecode Ceci contraste avec les langages plus traditionnels o u les

fonctions retournent toujours ellesmemes leur resultat Dans ces langages le mecanisme dapp el

est represente par la premiere des deux conversions CPS

Linteret dimplanter les app els terminaux tel que specie par le standard nest pas clair dans

lexemple Toutefois si on considere lexemple suivant on prend vite conscience de linteret de

cette methode dimplantation

define destructivereverse

lambda original new

if null original

new

let tail cdr original

setcdr original new

destructivereverse tail original

La fonction de cet exemple sert a renverser des listes par des mutations sur les paires Essentiel

lement cette fonction exprime un calcul iteratif Dans un langage comme C elle serait implante

avec une b oucle et trois variables Or ici il sagit dune fonction recursive Elle se rapp elle

recursivement p our chaque paire de la liste

On remarque que lapp el recursif se trouve en p osition terminale Si les app els terminaux ne

sont pas implantes comme le standard de Scheme lexige cette fonction utilise un espace prop or

tionnel a la longueur de la liste Sils le sont alors lexecution de la fonction demande seulement

un espace constant En termes de continuations la dierence vient du fait quune chane de

continuations inutiles est creee dans une mauvaise implantation Selon la representation interne

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

des continuations ceci represente soit un empilement dinformations deja rendues inutiles soit

la creation dune chane de structures de donnees inutiles

Impact sur linterprete

Comme dans le cas des continuations comme ob jets de premiere classe le traitement special

des app els terminaux imp ose des contraintes sur larchitecture dun interprete Scheme Cette

caracteristique ne se retrouve pas dans les langages plus conventionnels comme le C Donc en

general un app el en Scheme ne p eut etre simule par le mecanisme dapp el de C On le savait

deja a cause de la presence des continuations mais la presence des app els terminaux constitue

une raison supplementaire

Bien que ce traitement complique limplantation dun interprete il est preferable de leec

tuer Ce traitement special des app els terminaux est demande par le standard mais de plus il

constitue une facon deconomiser de lespace Un programme p our le microcontroleur a avan

tage a etre ecrit en utilisant au maximum des fonctions recursives terminales En eet le fait

deviter de sauver les informations necessitees par un retour inutile p eut rendre p ossible des

calculs demandant de nombreuses iterations Sans le traitement special ou en nutilisant que des

app els non terminaux la memoire reduite du microcontroleur se remplit vite

Gestion memoire

Tout systeme Scheme doit etre dote dun GC an de recuperer de lespace memoire En eet

il ny a aucune facon de liberer explicitement lespace o ccupe par un ob jet ou une variable Un

de nos ob jectifs consiste a implanter un GC temps reel p our eviter que des pauses se pro duisent

durant lexecution des programmes

La denition de GC temps reel change legerement dun auteur a lautre Cest p ourquoi

nous donnons la denition que nous avons adopte dans le cadre de la conception de notre GC

Ensuite nous discutons brievement de linteret dune telle denition

Denition

GC blo quant

Les GC conventionnels sont des GC blo quants Cestadire que la plus grande partie du

temps un tel GC nest pas en fonction Le systeme de gestion memoire alloue des ob jets a

lintention de lapplication jusqua ce quil ne reste plus despace libre Cest a ce moment que

le GC est declenche Celuici saccapare alors de tout le temps dexecution p our eectuer son

travail de recuperationde memoire Lorsquil a termine son cycle et quil a reconstitue une banque

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

despace libre et seulement a ce moment il redonne le controle a lapplication Celleci p eut

alors continuer a executer et entre autres a demander des allo cations dob jets Les moments

o u le GC fonctionne sont ceux o u lapplication est blo quee do u le nom de GC blo quant

Les blo quages de lapplication dependamment de la nature de celleci ne sont pas toujours

tolerables Cest la o u un GC temps reel prend tout son interet

Fonctionnement general dun GC temps reel

Un GC temps reel est un GC qui organise son travail de recuperation de la memoire de facon

a minimiser les blo quages quil cause a lapplication Au lieu de netre declenche que lorsquil ne

reste plus despace libre il est declenche a intervalles reguliers rappro ches mais il neectue a

chaque fois quune toute p etite partie du travail Son cycle nest donc pas fait de facon atomique

mais plutot est entremele avec le cours de lexecution de lapplication

Bien quun des ob jectifs dun GC temps reel soit de minimiser la duree des blo quages quil

cause a lapplication il nen reste pas moins quil se doit de remplir son role fondamental de

recuperation de memoire Lapplication ne doit pas manquer despace libre parce que le GC

fonctionne a un rythme trop lent Donc le GC doit etre invoque assez souvent et eectuer a

chaque fois une quantite susante de travail

Critere a resp ecter

Selon nous un GC temps reel doit resp ecter le critere que nous enoncons un p eu plus bas



Ce critere pro cede par comparaison Soit S un interprete Scheme dont le systeme de gestion

memoire comp orte un GC temps reel Soit S un interprete dont on a change le systeme de gestion

memoire par celuici un allo cateur pas de recuperateur operant sur une memoire innie non

initialisee



Le critere compare le temps necessaire p our faire une operation donnee sur S et sur S



Denotons par T et T les fonctions mesurant la duree de lexecution dune operation primitive



dans les interpretes S et S resp ectivement Le critere a resp ecter est le suivant il existe une

constante c telle que p our toute operation e sur des ob jets



T e cT e

Les operations concernees sont celles ayant trait a la creation et a la manipulation des ob jets

Ainsi on se restreint aux eets observables du GC temps reel Si on p ermettait que e soit

nimp orte quelle expression on inclurait les eets de choix dimplantation qui nont aucun lien

avec la gestion memoire Par exemple la representation des symboles des continuations etc

La constante c depend principalement de la quantite de memoire utilisee par des ob jets

vivants du programme Lorsquil y a plus dob jets vivants conserves par le programme le

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

tas est constamment plus rempli Un tas plus rempli necessite des cycles de GC plus frequents

Dans le cas dun GC temps reel ceci represente une plus grande quantite de travail a eectuer

a chaque periode de travail Donc une augmentation de la constante c Nous discutons plus

longuement de leet de lo ccupation memoire dans le chapitre sur le GC

Le critere devient trivial si lon p ermet a la fonction T davoir des images tres grandes Nous

supp osons que linterprete S est un interprete raisonnable Les exemples suivants illustrent

des temps raisonnables p our plusieurs operations de Scheme

Laccesdans une paire dans un vecteur ou la creation dune paire sont des operationsfaisables

en temps constants

T car T vectorref T cons O

Le calcul de la longueur dune liste et la creation dune liste dun vecteur ou dune chane

de caracteres sont faisables dans un temps prop ortionnel a la longueur de lob jet concerne

T length T list T makevector T makestring O n



Le critere fait donc en sorte que les operations dans linterprete S ont la meme complexite

que dans linterprete S

Interet de la denition

Cette denition est b eaucoup plus pres du p oint de vue du programmeur Scheme que de notre

p oint de vue dimplanteur de linterprete Cest ce qui fait son interet a notre avis Si lutilisateur

desire developper une application qui ait un temps de reponse court a certains moments donnes

il na qua preter attention aux operations que son programme eectue a ces momentsla Les

operations presumees rapides ne causent pas de blo quage a proprement parler Les operations

supp osant une recherche dans une structure de donnees ou une creation imp ortante dob jets

causent des blo quages dune longueur consequente

Il est imp ortant de comprendre que dans un systeme Scheme dote dun GC blo quant la

duree dune operation primitive nest pas previsible de cette facon En eet lorsquune operation

primitive declenche le GC blo quant celuici eectue surlechamp la recuperation dans tout le

tas La quantite de travail a faire lors de cette recuperation est generalement imp ortante et est

sans rapp ort avec la quantite de travail a faire par loperation primitive Lorsque le GC est

declenche durant une operation primitive la duree de celleci est augmentee signicativement

Il devient alors imp ossible de prevoir la duree de lexecution dun b out de programme

Traitement derreurs

Notre interprete ne resp ecte pas une des demandes du standard R RS a prop os des erreurs

dexecution Nous navons pas lintention de signaler les erreurs Par consequent nous ne nous

CHAPITRE DESCRIPTION PRECISE DE LOBJECTIF

o ccup ons pas de la detection derreurs non plus

De toute evidence ceci va a lencontre dun des avantages dutiliser Scheme que nous men

tionnons dans lintroduction Linterprete p eut se mettre a se comp orter bizarrement ou blo quer

si le programme en execution eectue une operation illegale

La raison ma jeure de ce choix vient encore de notre ob jectif de faire une implantation p our

microcontroleur Le microcontroleur nest normalement pas utilise p our fonctionner avec une

connexion a un terminal Le programme Scheme ou pas ne doit plus comp orter derreurs de

conception lorsquil est utilise p our diriger le microcontroleur dans sa tache Que le programme

ait ou non la p ossibilite de declarer quil ne fonctionne pas correctement ne change rien au fait

quil ne remplit pas sa tache et il est considere comme un echec

Une autre raison qui est plus une heureuse consequence quune raison est le fait quainsi

linterprete na pas a comp orter de co de de detection derreurs et sen trouve plus compact

Nous faisons donc lhypothese que le programme fourni par le programmeur est parfaitement

correct Cest p ourquoi nous considerons que notre implantation nest pas orientee vers le de

veloppement dapplications Un programme doit normalement etre developpe et teste sur une

machine plus puissante et sur une implantation de Scheme plus conviviale

Question decacite

Etant donne que la limite sur la taille de linterprete est une contrainte tres forte imp osee

par le microcontroleur nous avons vise une ecriture tres concise p our le noyau de linterprete et

la librairie standard Sans etre completement incompatibles la concision et lecacite en temps

sont plus ou moins inconciliables Nous ne visons donc pas une implantation particulierement

ecace en temps

Toutefois nous avons lintention de faire en sorte que le co ut de lutilisation de chaque

fonction de la librairie soit compatible avec ce que lon p eut esperer dune implantation rai

sonnable Nous presentons plus haut quelques exemples de temps dexecution attendus dune

implantation raisonnable section Nous ne les reprenons pas ici

CHAPITRE REPRESENTATION DES OBJETS

Chapitre

Representation des ob jets

Dans ce chapitre nous discutons de plusieurs asp ects lies a la representation des ob jets La

premiere section traite du typage des ob jets Scheme Ceci est une question centrale puisque

Scheme est un langage type dynamiquement Ensuite une breve comparaison est faite entre les

choix de representation des symboles et des continuations Finalement diverses representations

p our les environnements sont comparees Dans chaque comparaison nous mentionnons quelle

representation a ete choisie

Bien que les details dun choix de representation des ob jets soit tres reliee au type de GC

utilise nous essayons den rester le plus detaches p ossible

Representation des types

Il existe de nombreuses facons de representer les types dynamiquement De nombreuses

techniques sont presentees dans Gud Les deux premieres methodes que nous presentons

sont celles que nous utilisons dans dierentes versions de linterprete Il sagit de la representa

tion uniforme et de la representation taggee Dautres representations comme le typage par la

p osition dans le tas et par le regroup ement en pages dob jets du meme type ne semblent pas

convenir a nos exigences Nous ne discutons que brievement de ces dernieres

Representation uniforme

La representation la plus simple est sans doute la representation uniforme Les ob jets de

tous les types sont alloues dans le tas Tous les ob jets ont un premier champ qui enco de le type

Les champs suivants contiennent les informations qui comp osent lob jet Leur nombre et leur

signication dependent du type

CHAPITRE REPRESENTATION DES OBJETS

Par exemple une paire est representee comme suit

pair car cdr

un ob jet a trois champs contenant son type et les deux champs traditionnellement nommes car

et cdr En connaissant le type on en deduit que deux champs suivent et que ceuxci sont des

references a dautres ob jets Une chane de caracteres est representee comme suit

string length char char

Le type indique que le second champ est la longueur de la chane et que les champs suivants

contiennent des donnees brutes Le nombre de ces champs depend de la longueur de la chane

Cette representation a lavantage de p ermettre un traitement simple des ob jets a cause de

son uniformite Toutefois elle o ccasionne un certain gaspillage de memoire

Simplicite de traitement

Cette representation p ermet de simplier des taches comme lobtention du type ou de la

longueur lorsque cest le cas Mais cest surtout le GC qui est simplie

Comme tous les ob jets sont alloues et quils ont tous le type dans le premier champ le GC

na pas a reconnatre specialement chaque type dob jet Le format de chaque type p eut etre

enco de dans une table Le traitement de chaque ob jet se fait suivant les informations contenues

dans la table Cette appro che est adoptee dans les premieres versions de linterprete et p ermet

dobtenir un algorithme de GC extremement compact

Le champ de type p eut etre utilise p our contenir des bits a lusage du GC En eet il y a

p eu de types en Scheme donc il reste normalement des bits libres dans ce champ

Co ut eleve en espace

Malgre le fait que cette representation des types p ermette une manipulation simple des

ob jets et p ermette dimplanter les fonctions asso ciees de facon concise la representation prise

globalement nest pas particulierement compacte Cest dans la representation des ob jets les

plus courts que le gaspillage de memoire est le plus eleve Prenons quelques exemples an de

verier combien despace est pris

La paire est un ob jet contenant deux champs Sa representation uniforme comp orte donc

champs le type et les deux champs de reference de la paire Il y a un champ a joute a cause de

la representation Il ny a donc pas de probleme grave dans le cas de la paire

Regardons ce qui se passe avec le type number Nous rapp elons que nous ne voulons que des

entiers dans notre interprete De plus leur domaine est limite Lespace requis p our le sto ckage

dun nombre est un champ En representation uniforme le nombre prend la forme dun ob jet

alloue dans le tas et qui comp orte deux champs le type et le nombre Dans le cas du nombre

il y a une depense despace signicative Un ob jet de deux champs est cree p our contenir une

information aussi p eu volumineuse que le p ointeur qui le reference Toutefois le fait de remplacer

CHAPITRE REPRESENTATION DES OBJETS

un p ointeur par un nombre directement ne nous p ermettrait pas davoir linformation de typage

Il existe tout de meme de meilleures facons de representer les nombres comme nous le voyons

plus loin

Il est clair que dans le cas du type char la consommation de memoire est encore plus

imp ortante par rapp ort a la taille de la donnee a representer

Representation taggee

La representation taggee consiste a mo dier certains bits de la reference a un ob jet p our y

inscrire une information de typage Cep endant il doit rester p ossible de reconstituer ladresse

exacte de lob jet reference Lidee consiste a utiliser des bits de la reference qui ont toujours la

meme valeur quelle que soit la p osition de lob jet

Habituellement des bits constants existent p our deux raisons lalignement des ob jets la

taille du tas par rapp ort a la taille de lespace dadressage

Alignement

Supp osons que les champs ont une taille de o ctets chacun et quils se trouvent tous a des

adresses multiples de Il en decoule que les ob jets commencent necessairement a des adresses

multiples de Dans ce cas ladresse des ob jets une fois ecrite en binaire comp orte invariable

ment zeros dans les p ositions les moins signicatives On p eut donc adopter la convention que

les deux derniers bits dune reference a un ob jet sont utilises p our indiquer le type de lob jet

designe Ladresse de lob jet p eut etre retrouvee en masquant les deux bits de type

Taille du tas

Supp osons que le tas ait une grandeur de Ko ctets et que les p ointeurs les champs

comp ortent bits Or il sut de bits seulement p our identier sans ambigute tous les

emplacements dans le tas Par exemple si on decide de conserver la distance entre un ob jet et

le debut du tas plutot que ladresse propre de lob jet on na b esoin que de bits Comme seuls

bits sur sont utilises le bit le plus signicatif est toujours a zero Ce bit p eut servir a

contenir de linformation de typage Ladresse originale p eut etre retrouvee en commencant par

masquer le bit le plus signicatif etc

Soustypage

Lalignement et la taille du tas p euvent p ermettre de laisser certains des bits dadressage

constants Ces bits p euvent alors contenir de linformation de typage Lorsque ces bits sont

CHAPITRE REPRESENTATION DES OBJETS

susamment nombreux il est p ossible de trouver une combinaison distincte p our chaque type

Alors aucun ob jet na b esoin de soustypage

Lorsque les bits ne sont pas assez nombreux une combinaison donnee p eut servir a representer

plusieurs types distincts Dans ce cas un ob jet dun de ces types doit comp orter de linformation

de soustypage dans ses champs La solution la plus simple consiste a a jouter un champ de

soustypage devant un tel ob jet Cette methode est similaire au typage de la representation

uniforme Dautres solutions p euvent utiliser une representation taggee a nouveau p our enco der

le soustypage A priori tous les moyens sont b ons p our enco der linformation de typage avec

la representation taggee

Ob jets nonalloues

La representation taggee p ermet davoir des ob jets nonalloues En eet jusqua maintenant

nous navons parle que de taggage de references Mais il est p ossible de tagger des informations

brutes Il sut dadopter la convention que lorsque les bits de taggage ont une certaine valeur

cela signie que les autres bits ne representent pas une adresse mais plutot une information

brute

Par exemple si Scheme ne comp ortait que des nombres entiers a taille xe et des paires on

p ourrait decider quune reference dont le dernier bit est contient ladresse dune paire dans les

premiers bits et quune reference dont le dernier bit est contient la valeur dun entier dans

les premiers bits Dans ce cas les entiers ne seraient pas des ob jets alloues Toutefois il y a un

bit de moins p our enco der la valeur des entiers

Nombreux cas particuliers

Contrairement a la representation uniforme la representation taggee ne traite pas tous les

ob jets de la meme facon Les ob jets de certains types sont alloues dautres pas Certains ont

un soustype dautres pas

Souvent lirregularite inherente a cette representation fait en sorte quil faut des fonctions

specialisees p our chaque operation et p our chaque type La partie du GC est celle qui se com

plique le plus Chaque type p eut etre alloue ou non avoir un champ de soustype ou non en

plus du fait que le nombre de champs requis varie selon le type Donc lensemble des fonctions

reliees a la manipulation des dierents types de Scheme est normalement plus imp osante avec

la representation taggee quavec la representation uniforme

Il est imp ortant de mentionner quil est normalement plus complexe de manipuler les types

sous cette representation Cest habituellement vrai mais dans certaines implantations de sys

temes de gestion de la memoire il p eut arriver quil ny ait pas b eaucoup plus de travail a faire

Par exemple si les ob jets alloues sont toujours alignes sur des adresses qui sont des multiples

de alors il y a bits les moins signicatifs qui p euvent etre utilises p our le typage Ce qui

CHAPITRE REPRESENTATION DES OBJETS

p ermet denco der types dierents et est donc amplement susant p our le langage Scheme La

verication du type se fait toujours de la meme facon Par rapp ort a la representation uniforme

la routine de GC na qua faire un test de plus p our verier si un type donne a ses ob jets alloues

ou non

Toutefois sur une machine o u il manque de memoire on ne p eut se p ermettre dimp oser des

alignements imp ortants ni dutiliser des p ointeurs des champs trop volumineux Il est donc

inevitable que le taggage des ob jets soit irregulier Cest justement le cas du taggage que nous

employons dans notre interprete nal Il est decrit a la section

Economie despace

La representation taggee p ermet de realiser des economies de memoire par rapp ort a la

representation uniforme Meme si lensemble des fonctions manipulant les ob jets devient plus

volumineux la representation des ob jets dans le tas est moins volumineuse

On p eut constater une economie despace en regardant un exemple Supp osons que le passage

a la representation taggee p ermette deliminer dans les paires le champ de type Pour chaque

paire on a donc gagne la valeur dun champ Supp osons aussi que le passage a la representation

taggee cause une augmentation de o ctets de la taille du co de relie a la manipulation des

paires o ctets de co de compile p our une machine comme un microcontroleur p ermet da jou

ter une quantite raisonnable dinstructions Si on prend p our acquis que les champs ont o ctets

sur le microcontroleur il sut davoir alloue au moins paires p our commencer a faire des

economies de memoire Meme en accordant o ctets de plus p our le co de faisant la manipu

lation de chacun des types un millier de paires susent a comp enser p our laccroissement du

co de Un millier de paires est un nombre relativement p etit et laccroissement de o ctets de

la taille du co de p our le traitement de chaque type est une estimation vraiment p essimiste

Nous ne pretendons pas demontrer avec cet exemple que la representation taggee p ermet

des economies de memoire De toute facon les economies realisees dependent du type des ob jets

utilises Or la quantite dob jets des dierents types varie dun programme a lautre et il faudrait

alors xer une distribution de probabilite sur les dierents types p our avoir une mesure qui

vaille De facon concrete le passage de la representation uniforme a la representation taggee a

p ermis de realiser une economie despace appreciable dans le cas de notre interprete comme

nous le montrons un p eu plus loin

Reduction du domaine

Lutilisation de bits de tag p our typer les references aux ob jets p eut demander de reduire le

domaine de certains types Il sagit des types p our lesquels les ob jets ne sont pas alloues Les

bits de tag laissent moins quun champ complet p our enco der la donnee brute

Dans notre interprete le type number voit son domaine restreint par le taggage Comme

CHAPITRE REPRESENTATION DES OBJETS

cest un choix dimplantation de ne pas avoir de nombres de taille illimitee ce nest pas plus

arbitraire de xer la taille du domaine a une taille plus p etite que celle qui serait disp onible

si un champ complet etait utilise Malgre tout il est imp ortant de minimiser cette reduction

du domaine imp osee aux nombres Premierement parce que les mots sur le microcontroleur

ne sont que de bits Deuxiemement parce que les programmeurs habitues de programmer le

microcontroleur en assembleur ou en C y verraient une p erte de puissance trop imp ortante La

section montre le taggage utilise sur les references et en particulier le taggage des nombres

Les autres representations

Outre les representations uniforme et taggee il existe de nombreuses autres facons de typer

dynamiquement les ob jets Nous en decrivons deux brievement Il sagit du regroup ement en

zones selon le type et du regroup ement des ob jets en pages dob jets du meme type

La premiere technique consiste a separer lespace du tas en autant de zones quil y a de

types Lallo cation dun ob jet dun type donne doit se faire dans la zone corresp ondante et on

reconnat le type dun ob jet par la zone dont il fait partie De cette facon il nest pas necessaire

de tagger les references aux ob jets ni da jouter un champ de type a ces derniers

Les separations entre les zones p euvent etre xes ou etre mobiles et adaptables aux b esoins

courants du programme

Sur le microcontroleur il y a p eu despace et il nest pas envisageable dutiliser des sepa

rations xes entre les zones En eet un programme qui utilise principalement un des types de

Scheme se retrouverait tres rapidement a court despace p our ce type

Il faudrait donc utiliser des separations mobiles entre les zones De cette facon si le type le

plus utilise change avec le temps la taille des zones p ourra etre adaptee en consequence Cette

technique semble convenir Du moins jusqua ce que lon tente de la faire fonctionner avec un

GC temps reel Nous navons pas de solution simple a ce probleme et nous allons en discuter

plus longuement dans le chapitre sur le GC

La deuxieme technique que nous mentionnons est celle o u les ob jets sont regroupes par

pages dob jets du meme type Les pages sont des blo cs de memoire dune taille predenie et

qui debutent toujours a des adresses qui sont des multiples de la taille des blo cs Une entete se

trouve au debut de chaque page an dindiquer entre autres le type des ob jets de la page A

lallo cation dun ob jet dun type donne une des places libres dans une page dediee a ce type est

reservee Une page dediee au type en question doit etre creee sil ny a pas de place disp onible

dans les pages existantes Le type dun ob jet sobtient donc en retrouvant le debut de la page

qui le contient par un simple arrondissement et en lisant le type qui y est indique Les ob jets

euxmemes nont pas a avoir de champ de type et les references nont pas a etre taggees Des

cas particuliers doivent etre prevus p our gerer les chanes de caracteres et les vecteurs car ils

p euvent atteindre des dimensions plus grandes que les pages

CHAPITRE REPRESENTATION DES OBJETS

Type Enco dage Domaine

Entiers nnnnnnnnnnnnnnn a

Paires rrrrrrrrrrrrr max

Fermetures rrrrrrrrrrrrr max

Autres types alloues rrrrrrrrrrrrr max

Symboles nnnnnnnnnnnn max

Caracteres xxnnnnnnnn complet

Fonctions du noyau nnnnnnnnnn complet

Bo oleens xxxxxxxxxn complet

Liste vide xxxxxxxxxx complet

Les bits contenant ou sont ceux qui servent a indiquer le type Les bits

representes par un n sont des bits qui contiennent directement linformation dun

ob jet nonalloue Les bits representes par un r sont des bits qui contiennent ladresse

dun ob jet alloue Les bits representes par x ne servent ni p our le typage ni comme

information Ils sont arbitrairement xes a dans notre implantation

Fig Description du taggage

A nouveau nous voyons dans le chapitre sur le GC que nous navons pas de technique temps

reel simple qui puisse travailler sous une telle representation La simplicite de lalgorithme est

imp ortante car le co de du GC ne doit pas consommer tout lespace sauve grace a lutilisation

de la representation

Nos choix dimplantation

Les dierentes versions de notre interprete utilisent les representations uniforme et taggee

Les premieres versions utilisent la representation uniforme Nous ne prendrons pas la p eine de

decrire quel numero etait asso cie a chaque types Par la suite nous adoptons la representation

taggee Le taggage change un p eu dans les versions suivantes suite a des optimisations etc Nous

donnons ici un resume de la representation adoptee dans la derniere version voir la gure

Dans notre representation nale les ob jets devant etre alloues dans le tas sont les paires

les fermetures les continuations les vecteurs et les chanes de caracteres Les ob jets de tous les

autres types que lon app elle des types immediats ne sont pas alloues ils sont co des a meme

la reference Il y a des remarques a faire a prop os de certains types

Premierement les nombres ne sont pas alloues et nont quun seul bit de tag Il est imp ortant

de ne pas allouer les nombres dans le tas p our p ermettre deconomiser lespace Neanmoins nous

avons fait un eort particulier an dutiliser le moins de bits p ossible p our tagger les nombres

et de ne pas trop reduire le domaine des nombres Les nombres p euvent donc etre representes

sur le domaine a plutot que sur le domaine a que les bits dun

CHAPITRE REPRESENTATION DES OBJETS

Soustype Premier champ

Continuations rrrrrrrrrrrrrrr

Vecteurs llllllllllllll

Chanes de caracteres llllllllllllll

Le soustypage est fait en taggant le premier champ Dans le cas de la conti

nuation le soustype est co de avec le p oint de retour dans le co deo ctets r voir

section Dans les autres cas cest avec la longueur l quest co de le soustype

Cet enco dage limite les vecteurs et les chanes a des longueurs inferieures a La

taille du co deo ctets est limitee a o ctets a cause des bits alloues a lenco dage

de ladresse de retour dans les continuations

Fig Soustypage des objets regroupes sous le type Autres types alloues

champ complet ou mot de la machine p ermettent de representer La reduction du domaine est

donc minime

Deuxiemement il y a deux sortes de fonctions Scheme dans notre interprete les fonctions

du noyau et les fermetures Les premieres sont p eu nombreuses et corresp ondent aux fonctions

qui sont implantees directement dans le noyau de linterprete Les fonctions de base p our la

manipulation des ob jets des dierents types sont de ce nombre Les fonctions du noyau ne sont

pas allouees elles sont simplement representees par un numero de fonction tagge Les autres

fonctions de la librairie et les fonctions creees par le programme sont des fermetures Ce sont

des structures de donnees qui contiennent un p oint dentree et un environnement de denition

donc elles doivent etre allouees dans le tas en tant quob jet a deux champs

Troisiemement les continuations les vecteurs et les chanes de caracteres nont pas leur

propre tag Ils sont regroupes sous le tag autres types alloues et doivent p osseder un soustype

dans leur premier champ La gure montre les tags asso ciesa ces soustypes Les continuations

ont leur tag dans le meme champ que le p oint de retour voir section Les vecteurs et les

chanes ont leur tag dans le meme champ que leur longueur Il sagit des longueurs en nombre

de champs et en nombre de caracteres resp ectivement Les champs qui suivent contiennent soit

des references a des ob jets dans le cas des vecteurs soit des co des Ascii dans le cas des chanes

en nombre variable

Quatriemement les symboles sont des ob jets non alloues Un symbole nest en fait quun

numero tagge Nous discutons de la representation des symboles dans la pro chaine section

Le passage a la representation taggee p ermet normalement deconomiser de lespace memoire

Ce fut le cas p our notre interprete Toutefois il est dicile de faire une evaluation juste a ce

sujet car la representation des ob jets est fortement reliee au GC Certains GC p euvent avantager

certaines representations Par exemple meme si un ob jet alloue ne necessite pas de soustypage

le GC p eut faire en sorte quun champ supplementaire lui soit a joute tout de meme Nous

nous contentons de donner tout simplement lamelioration que nous avons observee lors du

CHAPITRE REPRESENTATION DES OBJETS

changement

Dans les versions o u nous faisons le passage dune representation a lautre un GC blo quant

a deux semiespaces est utilise De plus linterprete charge au depart toute la librairie Scheme

avant de p ouvoir executer des commandes tapees au clavier Cest la librairie qui constitue les

donnees utilisees p our mesurer la compacite de la representation Le fait de tagger les references

aux ob jets et de ne carrement plus allouer les types immediats p ermet dameliorer la repre

sentation des types suivants les nombres les symboles les caracteres les fonctions du noyau

les b o oleens et la liste vide Les paires et les fermetures ne p erdent pas de champs a cause

dexigences venant du GC Le champ de typage de la representation uniforme est conserve p our

p ouvoir sto cker le bit de marquage du GC Les chanes de caracteres p erdent un champ a cette

o ccasion Toutefois ceci nest pas d u au taggage mais plutot a un changement de representation

independant du typage Lespace o ccupe par la librairie passe denviron champs a environ

Les champs en question sont des mots machine de bits La plus grande partie de cet

espace est pris par les paires utilisees p our representer les expressions Scheme Ceci explique que

les amelioration app ortees par le taggage ne soient pas plus imp ortantes

Les symboles

Deux representations dierentes des symboles sont utilisees dans les versions de linterprete

De plus dans les premieres versions les symboles sont utilises p our contenir la valeur des va

riables globales du nom corresp ondant Dans les dernieres seul le nom du symbole reste

Contenant directement le nom

Cette facon de representer les symboles est probablement la plus immediate Il sagit sim

plement davoir un ob jet a deux champs un p our le nom et un p our la valeur de leventuelle

variable globale corresp ondante Le champ du nom contient une reference a une chane de ca

racteres Lorsquil ny a pas de variable globale corresp ondant au symbole le champ de la valeur

contient une valeur par defaut nous utilisons f Les expressions define et set mo dient ce

champ

De plus il faut maintenir une liste de tous les symboles existants dans linterprete Ceci est

necessaire car il ne p eut y avoir quun seul symbole dun nom donne Si une fonction comme

read ou stringsymbol doit retourner un symbole ayant le meme nom quun symbole existant

alors le symbole retourne est le symbole deja existant A chaque fois quun symbole dun nom

: Ceci nest pas parfaitement exact Le standard ne requiert pas explicitement quil sagisse du memeob jet Ce

qui est exige par le standard cest que les symboles ayant le meme nom soient equivalent au sens de eq Or dans

la plupart des implantations eq est implante a laide dune comparaison de p ointeurs donc tres ecacement

Une comparaison des noms lors dune comparaison entre symboles rendrait eq b eaucoup moins ecace Les

programmeurs Scheme sattendent en general a une implantation de eq tres ecace Cest p ourquoi nous nous

assurons de navoir quau plus un symbole de chaque nom

CHAPITRE REPRESENTATION DES OBJETS

encore inconnu est cree il est a joute a la liste

nom val nom val nom val

"foo"

Il est p ossible deviter lallo cation de la paire lors de chaque allo cation de symbole Il sagit

da jouter un champ a chaque symbole Ce champ sert a chaner les symboles en une liste Un

champ de plus par symbole est une depense de memoire moins imp ortante quune paire par symbole

nom val nom val

Il est p ossible de ne pas avoir de chane de caracteres p our chaque symbole en faisant en

sorte que les symboles euxmemes soient des ob jets a taille variable contenant directement leur

nom Cette representation est encore plus compacte que la precedente Toutefois le traitement

des ob jets a taille variable a tendance a etre complique comme nous le voyons dans le chapitre

sur le GC et il nest pas souhaitable da jouter un type a taille variable dans le systeme

Numerotation des symboles

Lautre facon de representer les symboles que nous utilisons consiste a assigner un numero

a chaque symbole Un symbole devient alors un entier tagge Le nom du symbole sous forme

de chane de caracteres Scheme est sto ckee dans un vecteur regroupant les noms de tous les

symboles Si la valeur des variables globales est sto ckee avec les symboles il sut davoir un

deuxieme vecteur qui regroup e toutes les valeurs Lorsque la fonction read ou stringsymbol

sapprete a retourner un symbole elle p eut verier lexistence du symbole en parcourant le

vecteur des noms Si les vecteurs sont pleins lors de la jout dun nouveau symbole de nouveaux

vecteurs plus longs sont alloues et remplacent les anciens

Cette representation est compacte Elle requiert le meme nombre de champs par symbole

que la representation suggeree o u un symbole est une structure a taille variable contenant le

nom la valeur et la reference au symbole suivant En eet ceci vient du fait que les vecteurs

sont des structures de donnees compactes Lorsquil y a susamment de symboles les vecteurs

deviennent longs et lespace pris en moyenne p our contenir le nom et la valeur sappro che de

champs On obtient donc une ecacite en espace presquaussi b onne que dans le cas de la

structure contenant toutes les informations mais sans introduire de nouveau type complexe a

manipuler Un numero tagge est tres simple a traiter par le GC

CHAPITRE REPRESENTATION DES OBJETS

Malgre tout levaluation de lespace pris par cette representation est plutot optimiste En

eet levaluation supp ose que les vecteurs contenant les noms et les valeurs sont pleins Cette

supp osition implique que les vecteurs doivent etre aggrandis a chaque allo cation de symbole Ceci

nest pas tellement ecace Ce que nous faisons donc en pratique consiste a allouer de nouveaux

fois plus grande lorsque les vecteurs actuels sont pleins Donc en vecteurs dune longueur

pire cas les vecteurs sont aux trois quarts pleins Lespace pris en moyenne sur lensemble des

champs en pire cas lorsque les symboles p our contenir le nom et la valeur sappro che de

vecteurs sont les plus vides Il est p ossible de diminuer le facteur daggrandissement ayant ainsi

moins de p erte despace mais augmentant la frequence des agrandissements des vecteurs

Cette representation des symboles est utilisee a partir de la version o u le taggage est utilise

p our typer les ob jets Le champ p our contenir la valeur de la variable globale est ab ondonne a

partir de la version o u linterprete nest plus interactif La compilation so ccup e didentier les

variables globales et leur espace est reserve de facon statique Dans un systeme compile il nest

pas necessaire de conserver le symbole nommant une variable sauf lorsque le systeme fournit

la fonction eval Toutefois cette fonction est nonstandard et ne se retrouve pas dans notre

systeme Il ny a donc plus de lien entre lexistence des symboles et des variables globales

Cette representation avec un ou des vecteurs a lavantage detre compacte En fait on p eut

rendre la taille moyenne de la representation de chaque ob jet aussi pro che que lon veut du

nombre de champs utiles de lob jet Par utiles nous designons les champs qui contiennent

linformation que doit contenir un ob jet par denition et non ceux qui ne servent qua des taches

administratives On p ourrait etre tente dutiliser cette representation p our les ob jets dautres

types Deux vecteurs p our representer les paires par exemple

Malheureusement les ob jets des autres types ne sont pas conserves indeniment comme les

symboles Un symbole une fois cree est conserve p our toute la duree de lexecution du pro

gramme p our assurer son unicite Avec les autres types les vecteurs se rempliraient rapidement

de champs dob jets abandonnes Il faudrait eectuer une collecte dob jets abandonnes a linte

rieur meme des vecteurs Cette representation nirait par avoir des defauts similaires a ceux de

la representation des types par regroup ement en zones voir section

Les continuations

La representation des continuations est fortement liee au mo dele dexecution utilise dans un

systeme Scheme Elle p eut donc changer radicalement dun systeme a lautre

Nous presentons trois facons dierentes de les representer La premiere consiste en une pile

La seconde en des fermetures La troisieme en des structures de donnees ad hoc Enn nous

decrivons la representation employee dans notre interprete

CHAPITRE REPRESENTATION DES OBJETS

Pile

Plusieurs implantations de Scheme utilisent une pile Celleci sert a faire le passage dargu

ments indiquer les p oints de retour etc Comme nous le mentionnons a la section il ny a

habituellement pas de facon p ortable dutiliser la pile du langage dimplantation Une pile doit

etre geree explicitement

Lorsque la continuation est reiee avec callcc une copie de la pile est creee dans le tas

Lactivation de cette continuation cause un remplacement de la pile actuelle par la pile sauvee

Cette representation est tres ecace lorsque les programmes nutilisent pas callcc Toute

fois lorsquil y a frequemment des reications de la continuation courante les copies demandent

b eaucoup de temps et despace car il ny a pas de partage dinformation entre les continuations

Malgre tout il existe des techniques plus sophistiquees qui eectuent les copies partiellement

au b esoin Un morceau de la pile nest sauve que lorsquil est sur le p oint detre detruit par le

depilement Ainsi la pile est copiee aussi p eu que p ossible Ces techniques rendent la reication

des continuations plus ecaces et moins gourmandes en espace memoire

Fermetures

Une facon de representer les continuations consiste a les rendre explicites par une conver

sion CPS Apres cette conversion toutes les continuations sont devenues des fermetures a un

argument

Lavantage principal de cette methode est deviter davoir a creer des ob jets du type conti

nuation explicitement Tout le mecanisme des continuations est pris en charge par des manipu

lations de fermetures De plus le probleme de la reication de la continuation courante devient

trivial La fonction callcc p eut etre impantee comme ceci en style CPS naturellement

define callcc

lambda proc k

proc lambda val k k val

k

Un inconvenient de cette methode est la conversion CPS Celleci a tendance a augmenter

signicativement la taille dun programme De nombreuses fonctions administratives sont intro

duites an deliminer completement lutilisation du retour de valeur Cette augmentation de la

taille du programme p eut etre attenuee lors de la compilation mais au prix danalyses assez p oussees

CHAPITRE REPRESENTATION DES OBJETS

Structures de donnees ad hoc

Au lieu deectuer une conversion CPS du programme et de ramener les continuations a des

fermetures on p eut creer un type continuation dont les ob jets sont manipules de facon interne

et contiennent le meme genre dinformations que les fermeturescontinuations

Le detail des champs dune structure de type continuation depend enormement du mo

dele dexecution du systeme Scheme Habituellement le mo dele dexecution est celui dune ma

chine virtuelle Cette machine virtuelle p ossede quelques registres detats et sait faire un certain

nombre doperations

Un des registres contient toujours une reference a la continuation courante Un ob jet de type

continuation est cree chaque fois que la machine sapprete a eectuer une serie doperations

qui risquent de mo dier letat de ses registres Par exemple un app el nonterminal demande

generalement la sauvegarde de letat de la machine dans une continuation

La creation dune continuation cause entre autre la sauvegarde du p oint de retour et de la

continuation courante Le chanage des structures de continuation p ermet ainsi de faire lequi

valent dun empilement A proprement parler la continuation est la chane des structures

Le retour du resultat dun calcul entrane le retablissement des registres a letat sauve dans

la premiere structure de la chane

Cette representation a lavantage deviter une conversion CPS Mais elle necessite la creation

dun type continuation La reication demande de sauver letat actuel dans une continuation et

denvelopper celleci dans une fonction Linvocation de cette fonction cause le remplacement de

letat de la machine par letat sauve La reication et linvocation dune continuation sont donc

tres p eu co uteuses en temps et en espace

Nos choix dimplantation

Nous utilisons une representation avec des structures de donnees ad hoc dans toutes les

versions de linterprete Premierement ce choix semble raisonnable a priori Il nest pas evident

de decider laquelle des representations est la plus compacte bien que celle utilisant des fermetures

semble moins b onne La representation a pile est la meilleure lorsquil ny a pas de reications

puisque toutes les donnees sauvees sont contigues comme dans un vecteur Toutefois notre

implantation p ermet lutilisation de callcc et il faut prevoir le cas o u la reication est utilisee

La representation a pile implantee de facon bete demande trop despace Mais une implantation

plus sophistiquee p ourrait etre plus avantageuse que la representation par des structures ad hoc

Deuxiemement il est plus facile de gerer un tas quune pile et un tas Dans le cas o u une pile

est utilisee il y a deux regions de taille variable qui se disputent le p eu de memoire disp onible

Une division xe entre les deux regions ne p ermet pas de sa juster aux uctuations dallo cation et

dempilement La gestion dune frontiere mobile rend le travail du GC particulierement complexe

CHAPITRE REPRESENTATION DES OBJETS

Troisiemement comme la representation des continuations est au co eur de linterprete un

changement de representation entrane des changements ma jeurs dans linterprete Cest p our

quoi nous navons pas essaye dautres representations

Nous ne decrivons pas le contenu precis de la structure que nous utilisons La machine

virtuelle utilisee est decrite a la section La liste des registres qui sont sauves dans une

continuation y est donnee

Les environnements

Avant de commencer nous tenons a preciser que nous parlons des environnements lexicaux

dans cette section et non de lenvironnement global Pour eviter une lourdeur inutile nous

utilisons le mot environnement p our designer les environnements lexicaux

Il existe de nombreuses facons de representer les environnements de Scheme Dans certains

systemes plusieurs representations sont utilisees conjointement Une representation donnee est

utilisee tout dependant de lusage prevu dun environnement Nous voyons ici plusieurs facons

distinctes de representer les environnements Nous indiquons ensuite les choix que nous avons

faits

Listes dasso ciation

La representation par des listes dasso ciation est probablement la plus intuitive Il sagit de

listes dont chaque element est une paire contenant un symbole le nom et un ob jet Scheme la

valeur Commencons avec un exemple simple

let x y x y

Au moment de faire la somme de x et y lenvironnement courant EC a lasp ect suivant

EC

y 8 x 7

Lorsque linterprete recherche la valeur de x il parcourt la liste asso ciative jusqua la paire

contenant le symbole x Il fait de meme p our y Similairement lorsque linterprete rencontre une

expression set operant sur une variable lexicale il recherche dans lenvironnement courant la

paire corresp ondant au nom de la variable aectee

En Scheme il est p ossible de masquer lo calement une variable dun certain nom en ayant

CHAPITRE REPRESENTATION DES OBJETS

une liaison a une nouvelle variable du meme nom Prenons cet exemple

let a b

let c b

a b c

EC

c 7 b 8 a 5 b 6

La reference a la variable b dans la somme concerne la variable b qui est liee dans le let

interne Ceci est reete dans la representation par le fait que les variables les plus nouvellement

liees sont a joutees a la tete de la liste La recherche des variables se fait toujours en commencant

a la tete de la liste De cette facon lacces aux variables resp ecte la semantique de Scheme

Dans le cas dun acces a une variable globale le symbole nommant la variable ne se trouve tout

simplement pas dans la liste dasso ciation

Lorsque levaluation ressort dune forme de liaison lenvironnement courant revient a un etat

anterieur Ce sont les continuations qui contiennent linformation necessaire Il ny a donc pas

delimination explicite des variables dans lenvironnement courant il y a simplement des retours

aux environnements anterieurs

Il est assez clair que cette representation nest pas la meilleure Le fait de fouiller la liste

asso ciative a la recherche dun symbole constitue un travail relativement imp ortant et fait p erdre

de lecacite De plus cette representation demande deux paires par variable Elle est donc p eu

compacte Un programme utilisant b eaucoup de fermetures et de formes de liaisons remplit plus

rapidement son espace memoire Elle a toutefois lavantage de ne pas requerir de pretraitement

sur les expressions aevaluer Toutes les representations qui suivent demandent un pretraitement

Les environnements ainsi representes ont la propriete de p ouvoir partager la queue de leur

liste Cest aussi vrai p our plusieurs des representations qui suivent Un exemple du partage des

queues est presente p our la pro chaine representation

Listes

Une des caracteristiques de Scheme est la p ortee lexicale des variables La p ortee lexicale

p ermet de determiner de facon statique a la compilation la variable concernee par une reference

ou une aectation

Cette representation est presquidentique aux listes dasso ciation La dierence principale

vient du fait que la liste representant lenvironnement ne contient pas des asso ciations mais des

valeurs uniquement Dans ces listes il ny a pas le nom de chaque variable Donc une variable

nest pas recherchee par son nom mais par sa p osition dans lenvironnement Reprenons cet

CHAPITRE REPRESENTATION DES OBJETS

exemple

let a b

let c b

a b c

EC i EC e

7 8 5 6

Lorsque lon se trouve dans le let externe et hors du let interne lenvironnement est repre

sente par une liste de deux elements EC Le premier element est la valeur de a et le deuxieme

e

est la valeur de b Lorsque lon se trouve dans le let interne lenvironnement est une liste de

quatre elements EC Le premier c le deuxieme b le troisieme a le quatrieme ne p eut etre

i

accede et est la valeur de la variable b masquee

Cette representation p ermet des acces plus rapides aux variables en eliminant la recherche des

symboles nommant les variables De plus cette representation ne p eut etre que plus compacte

que celle des listes dasso ciation En eet une seule paire est requise par variable

Les environnements representes par des listes p euvent partager la queue de leur liste Lors

de linterpretation dun programme il y a plusieurs environnements qui existent simultane

ment lenvironnement courant les environnements de denition des fermetures les environne

ments sauves par les continuations Des environnements partagent leur queue lorsquils ont des

instances de certaines variables en commun Prenons par exemple le cas des deux fermetures

sto ckees dans la paire

define makethunk

let delta

lambda epsilon

lambda

cons makethunk makethunk

Les deux fermetures ont un environnement contenant deux variables delta et epsilon Ces

variables ne sont pas traitees de la meme facon La variable delta est la meme p our les deux

fermetures Ce nest pas le cas de la variable epsilon En eet si une des deux fermetures

mute la variable delta lautre p eut voir le changement en lisant delta Toutefois si une des

fermetures mute sa variable epsilon lautre ne p eut le constater Cest que la variable delta

est creee une fois p our toutes lors de la denition de makethunk Tandis que la variable epsilon

est creee a chaque fois que makethunk est app elee Le graphique suivant illustre letat des listes

representant lenvironnement de chacune des fermetures ED et ED sont les environnements

CHAPITRE REPRESENTATION DES OBJETS

de denition des deux fermetures

2 ED1 8 3

ED2

Le partage de la queue des listes se pro duit aussi avec les representations par listes dasso

ciations et par blo cs chanes

Blo cs de liaison chanes

Cette representation est une variante de la precedente Plutot que de systematiquement

allouer chaque variable dans une paire separement on p eut regroup er les variables liees simul

tanement dans un vecteur Comme le vecteur est plus compact quune liste de meme longueur

a partir de elements et plus on p eut ainsi economiser de lespace

Les variables qui sont liees simultanement sont celles liees dans un let ou un letrec ou

encore lors de linvocation dune fermeture a plusieurs parametres Evidemment des formes let

ou letrec ne liant quune seule variable ne p euvent pretendre lier des variables simultanement

La forme let ne lie pas ses variables de facon simultanee Comme il est decrit dans le R RS

une forme let a plusieurs variables est semantiquement equivalente a une serie de formes let

embotees les unes dans les autres

Lorsquun blo c ne contient quune variable cest une paire qui sert a representer la variable

Quand la variable est liee la paire est a joutee devant lenvironnement courant Lorsquun blo c

contient plusieurs variables cest un vecteur qui represente les variables Le vecteur contient

une case par variable et une autre case qui sert a p ointer sur le reste de lenvironnement Cest

p ourquoi nous disons que cette representation consiste en des blo cs de liaison chanes

La p osition dune variable depuis un certain p oint du programme p eut etre decrite par le

nombre de blo cs a sauter et la p osition dans le blo c concerne Une variable dans un blo c a une

variable a systematiquement la premiere et seule p osition Nous tenons a faire cette observation

triviale parce quelle a une imp ortance dans la section sur le co deo ctets section

Par exemple la p osition de la variable x a partir de lendroit o u seectue laddition est

deuxieme blo c premiere p osition

let x y z

let a b

a b x y z

CHAPITRE REPRESENTATION DES OBJETS

EC 8 10 3 5 2

Cette representation a un double avantage sur celle utilisant les listes Les variables p euvent

etre atteintes un p eu plus rapidement lorsque lenvironnement est imp osant Et surtout il y a

une economie despace dans la representation des blo cs de liaison dau moins deux variables

Les blo cs de liaison p euvent etre partages de facon analogue a ce qui se pro duit dans le cas de

la representation par des listes

La representation a un leger defaut telle que nous la presentons Le dernier blo c dun envi

ronnement contient lui aussi une case p our referencer un eventuel blo c suivant Ce defaut p eut

etre corrige en faisant en sorte que le compilateur indique a la machine virtuelle quun acces est

fait a un blo c nal donc que la representation de celuici est legerement dierente

Blo cs de liaison avec display

Cette representation ressemble b eaucoup a la precedente La dierence vient du fait quun

display est a joute a chaque blo c Un display contient un p ointeur vers chacun des blo cs dac

tivation qui suivent dans la chane cestadire vers les blo cs dactivation des formes de liaison

englobantes Le display est typiquement implante avec des champs reserves au debut du blo c

Plus il y a de blo cs qui suivent dans la chane plus il y a de champs qui doivent etre reserves

Cette representation p ermet datteindre nimp orte quelle variable en temps constant a partir

du blo c du depart il faut emprunter au plus une fois le display p our rejoindre le blo c approprie

ensuite il sut de lire le b on champ dans le blo c rejoint La representation p ermet daugmenter

lecacite des acces aux variables Toutefois elle demande plus despace la plupart du temps

Du moins elle ne p eut etre plus compacte que la representation par des blo cs chanes En fait a

chaque fois quun blo c est suivi par plus dun autre dans la chane il est plus volumineux que le

blo c corresp ondant dans la representation sans display Comme la consommation despace est

p our nous un critere b eaucoup plus imp ortant que lecacite cette representation est moins

interessante

Representation plate

Cette representation concerne uniquement les environnements sto ckes dans les fermetures

Elle ne sut pas a representer lenvironnement devaluation courant On p ourrait donc lutiliser

dans le cadre dune representation mixte

Dans cette representation les environnements des fermetures sont constitues dun tableau

pas necessairement un vecteur Scheme ayant une case p our chaque variable de lenvironnement

de denition Au moment de la creation de la fermeture la valeur de chaque variable est copiee

dans la case appropriee du tableau Un soin particulier doit etre app orte aux variables mutables

CHAPITRE REPRESENTATION DES OBJETS

Les variables mutables sont celles qui sont susceptibles detre mo diees par une expression set

En eet si deux fermetures ont dans leur environnement de denition la meme instance dune

certaine variable les mutations app ortees a cette variable par une fermeture doivent etre visibles

depuis lautre fermeture Dans un tel cas ce nest pas la valeur de la variable qui est directement

copiee mais une reference a une bote contenant la valeur de la variable La b ote en question

est un ob jet a un champ alloue dans le tas et servant a contenir la valeur dune variable Par

exemple la fonction countedbinop denie et representee un p eu plus bas capture les variables

binop et counter Cette derniere est mutable et est conservee dans une b ote

define countedbinop

let binop getbinop

counter

lambda x y

set counter counter

binop x y

counted-binop: # 0

code du corps

A prime ab ord cette representation p eut sembler causer un gaspillage de memoire imp ortant

Lenvironnement courant est copie a chaque creation de fermeture et des b otes doivent etre

allouees dans le cas des variables mutables Mais ce nest pas exactement ce qui se passe En

eet il est p ossible grace a des informations obtenues lors de la compilation de ne copier dans

lenvironnement de la fermeture que les variables p ouvant etre utiles Ces variables sont celles qui

sont accedees depuis le corps de la fermeture Toutes les autres ne p euvent inuencer levaluation

du corps En quelque sorte la fermeture a sa creation selectionne les variables qui la concerne

La representation est decrite dans FL

Comparaison avec la representation par des blo cs chanes

Meme si cette representation a lavantage de p ermettre des acces plus rapide aux variables

fermees capturees lors de la creation de la fermeture le critere primordial reste lespace Sur

ce p oint il est plus dicile de comparer les deux techniques

Les deux exemples qui suivent montrent que les deux representations ont leurs avantages

Voyons le premier exemple

define makethunk

lambda a

let b f a

CHAPITRE REPRESENTATION DES OBJETS

c f b

d f c

lambda g d

La fonction makethunk sert a retourner des fermetures a aucun parametre dont le com

p ortement est determine par la variable fermee d Les variables a b c et d sont les variables

de lenvironnement lors de la creation dune fermeture Dans la representation par des blo cs de

liaison chanes lenvironnement de denition sauve consiste en une chane de blo cs de va

riable Dans la representation plate seul lespace p our contenir la variable d est requis puisque

les autres variables presentes dans lenvironnement ne p euvent inuencer lexecution du corps

de la fermeture Dans cet exemple la representation plate est clairement gagnante Cest grace

a la selection des variables a conserver Voyons le deuxieme exemple

define makethunk

let a f

b f

c f

lambda d

lambda list a b c d

La fonction makethunk sert aussi a retourner des fermetures a aucun parametre Mais

cette foisci les fermetures ont un comp ortement qui depend des variables presentes dans

lenvironnement de denition Dans la representation avec les blo cs chanes lenvironnement

sauve dans les fermetures consiste en un blo c contenant d suivi dun blo c contenant a b et c

Le second blo c nest pas alloue a la creation de chaque fermeture il est commun a toutes les

fermetures p ouvant etre creees Dans la representation plate un tableau contenant les variables

doit etre alloue a la creation de chaque fermeture La representation par des blo cs est gagnante

cette foisci Cest grace au partage des blo cs dactivation communs

Aucune des deux representations ne p eut pretendre etre toujours meilleure que lautre Il

faudrait faire de nombreux tests p our montrer quen moyenne sur de nombreux programmes

representatifs il y a une representation qui se distingue par rapp ort a lautre Dans la plupart

des articles o u est developpee une representation les auteurs p orte leur attention presquexclu

sivement sur lecacite Nous navons pas entrepris de faire detude p oussee p our determiner la

meilleure des deux representations

Nos choix dimplantation

Les versions interactives de linterprete utilisent la representation par des listes dasso ciation

etant donne que cette representation ne requiert pas de pretraitement

Les versions suivantes utilisent la representation par des blo cs de liaison chanes Cette repre

sentation p eut etre utilisee dans tous les contextes et non pas seulement p our les environnements

de denition des fermetures Il ny a donc quune seule methode dacces aux variables a inclure

CHAPITRE REPRESENTATION DES OBJETS

dans le noyau de linterprete De plus il nest pas necessaire dinclure quelquinformation que

ce soit p our la creation des fermetures car il ny a pas de selection de variables a faire

CHAPITRE RECHERCHE DUN GC ADEQUAT

Chapitre

Recherche dun GC adequat

La recherche dun GC p our notre interprete est une des parties imp ortantes du travail

En eet nous preferons avoir un GC temps reel p our p ermettre un deroulement regulier de

lexecution De plus il est imp ortant que la methode retenue soit relativement simple puisque

nous ne p ouvons accepter une implantation du GC trop volumineuse Aussi elle doit laisser la

chance dadopter une representation des ob jets qui soit compacte

La pro chaine section explique la necessite davoir un GC compactant Apres nous men

tionnons les principaux problemes lies a la realisation des GC temps reel Ensuite dierentes

p ossibilites sont mentionnees et classees Enn nous decrivons en detail la technique que nous

avons adoptee en b out de ligne

Limp ortance deviter la fragmentation

Nous decrivons tout dab ord ce quest la fragmentation La fragmentation dans un espace

memoire est une repartition des ob jets qui fait en sorte que lespace p eut contenir moins dob jets

que si la repartition etait optimale Elle se pro duit lorsque lespace libre est reparti en plusieurs

p etits morceaux entre des ob jets alloues et que les morceaux ne sont pas assez gros p our recevoir

certains ob jets Par exemple un espace memoire de champs contenant seulement paires

placees a intervalles reguliers p eut etre incapable daccepter des vecteurs dune longueur dune

centaine de champs alors meme quil reste plus de champs libres au total Il est clair que

nous ne p ouvons tolerer la fragmentation dans le p eu despace memoire dont disp ose notre

interprete

Il est p ossible deviter les mefaits de la fragmentation en contraignant tous les ob jets a avoir

la meme longueur Dans ce cas lespace libre se brise quand meme en multiples morceaux avec

le temps mais ce decoupage ne nuit pas a la capacite de lespace memoire Cest parce que

tous les b outs despace libre ont necessairement une longueur qui est un multiple de la longueur

CHAPITRE RECHERCHE DUN GC ADEQUAT

des ob jets Ils p euvent tous eventuellement servir a loger des ob jets De cette facon on nevite

pas un eparpillement des ob jets dans lespace memoire mais il na aucun eet nuisible sur la

capacite de ce dernier

Malheureusement en Scheme il nest pas p ossible de se conformer a une contrainte aussi

forte Les ob jets nont pas tous la meme taille Et surtout les ob jets a taille indeterminee comme

les vecteurs et les chanes de caracteres nont pas de limite de taille Il nest donc pas p ossible

de xer une taille unique p our tous les ob jets Une autre appro che p ourrait consister a diviser

lespace memoire en deux sections une p our les ob jets a taille xe et une p our les vecteurs et

les chanes Il faudrait decreter que tous les ob jets a taille xe ont la meme taille celle du plus

grand ob jet Ce decret entranerait un gaspillage imp ortant despace

Une autre solution a la fragmentation est dutiliser un GC qui ait une phase de compactage

des ob jets A chaque cycle le GC deplace certains ou tous les ob jets an de les regroup er en

un seul blo c laissant tout lespace libre en un autre blo c Nous nous interessons donc aux GC

compactants

Les dicultes liees aux GC temps reel

Il y a plusieurs dicultes liees a lutilisation dun GC temps reel Les dicultes que nous

mentionnons ici sont les incoherences creees par le GC durant son cycle les mutations eectuees

par lapplication le traitement des grands ob jets et la vitesse de travail necessaire p our recuperer

de lespace libre avant quil nen manque

Dans ce chapitre lorsque nous parlons de lapplication nous excluons normalement le GC

Lapplication et le GC p euvent etre vus comme deux programmes en execution entrelacee

Lincoherence des donnees

Le GC eectue plusieurs operations sur les donnees presentes lorsquil eectue son cycle de

collecte Une application dotee dun GC blo quant ne p eut tomber sur des donnees dans un

etat incoherent Mais lorsque le GC est temps reel lapplication continue a fonctionner p endant

que le GC remanie les ob jets dans lespace memoire Les donnees p euvent etre dans un etat

incoherent p our plusieurs raisons Les ob jets sont normalement marques dune facon ou dune

autre Ils sont deplaces lorsque le GC utilise deplace les ob jets ce qui est toujours le cas p our

un GC compactant La nouvelle p osition suite a leur deplacement doit etre indiquee dune facon

ou dune autre

Il est normalement simple de faire en sorte que les operations de lecture et decriture fonc

tionnent bien malgre que des bits de marquage soient allumes Un probleme plus dicile est de

sassurer que tout ob jet soit rapidement accessible meme sil vient detre deplace En eet il

est normal davoir plusieurs references a un meme ob jet Lorsque cet ob jet se fait deplacer il

CHAPITRE RECHERCHE DUN GC ADEQUAT

nest generalement pas p ossible de mettre a jour toutes les references a lob jet immediatement

Ceci vient du fait que les periodes durant lesquelles le GC p eut travailler sont habituellement

courtes Celuici ne p eut se p ermettre de traverser tout le tas p our mettre a jour les references a

chaque fois quun ob jet se fait deplacer Il est donc vital de prevoir un mecanisme qui p ermette

au GC davertir lapplication quun ob jet vient de changer de p osition

Les mutations faites par lapplication

Les GC temps reel ne ramassent pas toujours les ob jets qui meurent durant le cycle meme

En eet un ob jet p eut etre rejoint tres tot durant le cycle du GC Il est alors marque et evite

detre collecte durant ce cycle Mais il p eut devenir inaccessible avant meme la n du cycle Ce

type de situation fait en sorte que des ob jets morts survivent au cycle du GC Toutefois il sont

assures detre ramasses au cycle suivant Ce nest donc pas un probleme serieux Les GC temps

reel ont normalement tendance a conserver une partie des ob jets morts un cycle de plus que ne

laurait fait un GC blo quant Ce comp ortement est app elle le conservatisme

Le probleme inverse quant a lui doit etre evite a tout prix un GC ramassant un ob jet

qui etait encore vivant Ce probleme semble tellement grossier quaucun concepteur de GC ne

devrait commettre cette erreur Pourtant dans le cas dun GC temps reel il nest pas trivial de

sassurer de ne pas commettre lerreur Le probleme vient du fait que lapplication continue a

executer durant le cycle du GC Lapplication p eut faire des mutations dans les ob jets et tenter

de cacher un ob jet vivant aux yeux du GC

Voici comment cela p eut se pro duire Supp osons que le GC est en train de rechercher les

ob jets vivants que la paire A na pas encore ete rejointe et que la paire B a ete rejointe fouillee

et ne sera plus fouillee a nouveau Nous app elons fouiller laction dexaminer des champs a la

recherche dob jets non marques Ensuite lapplication mute la paire B an quelle contienne la

paire A et eace toute autre reference a cette derniere Il en resulte que la paire A est vivante

mais elle ne sera pas marquee et sera donc ramassee dici la n du cycle

Il existe plusieurs moyens de prevenir ce probleme On utilise ce quon app elle des barrieres

Il existe des barrieres en lecture et des barrieres en ecriture Il est p ossible dutiliser des bar

rieres dune ou des deux sortes dans une application Les barrieres en lecture ont comme eet

dempecher lapplication de manipuler directement des ob jets qui nont pas ete rejoints Les

ob jets manipules sont rejoints surlechamp ou pro chainement sils ne letaient pas encore Les

barrieres en ecriture ont comme eet de declarer au GC toute mutation eectuee an que celuici

puisse en tenir compte Il existe de nombreuses barrieres en ecriture Nous nentrons pas dans

les details ici

CHAPITRE RECHERCHE DUN GC ADEQUAT

Les grands ob jets

En Scheme les vecteurs et les chanes de caracteres sont des ob jets qui p euvent etre ar

bitrairement longs Lorsque le GC fouille ou deplace un long ob jet il doit p ouvoir susp endre

temp orairement ses activites p our p ermettre a lapplication de continuer Le deplacement sur

tout est une tache delicate Un ob jet a moitie deplace doit etre manipulable par lapplication

malgre tout Le GC doit etre en mesure davertir lapplication quun ob jet est presentement

coupe en deux et il doit laisser des informations susantes p our p ermettre de retrouver les deux

b outs

Reglage de la vitesse du GC

Ce probleme est crucial Il faut trouver un equilibre dans le reglage de la vitesse de travail

du GC Un GC trop rapide consomme du temps de pro cesseur inutilement Un GC trop lent

risque de ne pas fournir despace libre a temps p our p ermettre la p oursuite de lexecution

Les dierentes appro ches

La plupart des techniques de GC temps reel que nous avons trouvees dans la litterature sont

soit des GC a deux semiespaces soit des GC qui necessitent que les ob jets aient tous la meme

taille et parfois meme elles imp osent ces deux contraintes a la fois

Nous ab ordons dierentes appro ches en les classant par categories et nous discutons de leur

interet p our notre interprete En ce qui concerne les appro ches sur lesquelles il ny a rien ou

presque nous tentons tout de meme devaluer leur interet Nous ne pretendons pas faire la preuve

que nous evaluons parfaitement les dierentes p ossibilites mais nous essayons dapp orter des

arguments raisonnables p our ou contre ces p ossibilites

Nous commencons par les appro ches o u les ob jets sont regroupes en zones ou en pages

dob jets en fonction du type Ensuite les autres appro ches decrites sont celles o u les ob jets de

tous les types sont ensemble dans une ou deux grandes zones Les GC a deux semiespaces sont

decrits avant les GC a un seul espace

Regroup ement en zones ou en pages

Lors de notre recherche dans la litterature nous navons pas trouve de description de sys

teme utilisant une de ces organisations memoire tout en etant dote dun GC temps reel Nous

commentons tout de meme quelque p eu sur ces appro ches

Nous ab ordons brievement ces organisations de la memoire dans la section sur la represen

tation des types section Il imp orte den donner un bref rapp el Le regroup ement en

CHAPITRE RECHERCHE DUN GC ADEQUAT

zones consiste a separer le tas en autant de zones quil y a de types dob jets La zone contenant

un ob jet determine son type On p eut soit separer le tas de facon denitive ou bien p ermettre

que les frontieres entre les zones glissent an de sa juster aux uctuations des taux dutilisation

des dierents types Le regroup ement en pages consiste a separer le tas en pages de taille pre

denie Chaque page p eut etre libre ou bien comp orter des ob jets dun seul type Cest la page

qui contient un ob jet qui determine son type

Nous avons vu que ces organisations ont un certain avantage du p oint de vue de la compacite

Dans le cas du regroup ement en zones aucune mention du type nest necessaire sur les ob jets

Dans le cas du regroup ement par pages le type ne doit etre indique que sur chaque page Comme

les pages ont toutes la meme taille on retrouve facilement le debut de la page contenant un ob jet

et le type qui lui est asso cie

Malheureusement il ne semble pas evident dutiliser ces organisations memoire en conjonc

tion avec un eventuel GC temps reel tout en gardant les choses raisonnablement simples

Meme sans utiliser de GC temps reel la technique de regroup ement en pages ne p eut gerer

adequatement les ob jets a longueur variable de Scheme En eet il est tout a fait p ossible

que lon veuille allouer un vecteur ou une chane plus long que la taille des pages Il faudrait

donc prevoir une zone a part p our ces ob jets Dans les moments o u les longs ob jets seraient

intensement utilises il faudrait faire disparatre des pages an de liberer de lespace Dans les

situations inverses il faudrait sassurer que les longs ob jets soient periodiquement compactes a

un b out du tas p our p ermettre la creation de nouvelles pages Il faut noter que la partie du GC

traitant ce cas est deja aussi complexe quun GC compactant a un espace Une fois que lon veut

un GC temps reel les choses se compliquent encore plus Nous ab ordons plus loin les dicultes

qui emergent lorsquil faut eectuer un compactage en temps reel a linterieur meme dun seul

espace

Lorganisation memoire par pages demande dans un p etit tas comme celui dont disp ose

linterprete que les ob jets soient regroupes dans le plus p etit nombre de pages p ossible ou

presque En eet sil ny a pas de regroup ement de ce genre qui est eectue un type ab ondant

auparavant risque de monop oliser toutes les pages Par exemple sil y a b eaucoup de paires a

un moment donne et que la plupart sont ensuite liberees il p eut en rester une ou deux par pages

et ceci demande la conservation de toutes les pages p our ces quelques paires Le fait de deplacer

les ob jets dune page a lautre p ose le probleme de la mise a jour des references De plus il faut

p ouvoir deplacer les pages ellesmemes an de liberer de lespace p our la zone des longs ob jets

Lorganisation par zones semble plus simple a ab order Son probleme principal est lie a

la diculte a sadapter aux changements des taux dutilisation des dierents types On p eut

envisager qua la n de chaque cycle le GC laisse chaque zone avec une taille prop ortionnelle a

lutilisation de son type Ainsi chaque zone aurait le meme p ourcentage despace libre Mais si

un type reste p eu utilise jusque la devient p endant une periode le seul type alloue le GC doit

se mettre a travailler a un rythme terriblement eleve En eet un type p eu utilise prend p eu

despace donc sa zone est minuscule et son espace libre lest aussi

CHAPITRE RECHERCHE DUN GC ADEQUAT

Si autrement on decide que le GC laisse chaque zone avec la meme quantite despace libre

celuici na pas a se mettre a travailler a un rythme fou a la suite dun malheur Le probleme

est quil y a normalement des types plus utilises que dautres comme les paires et que le GC

doit travailler rapidement parce les zones asso ciees a ces types se remplissent vite

Ou encore on p ourrait guider le comp ortement du GC avec des observations savantes uti

lisant les probabilites et visant a reduire lesperance de sa vitesse de travail Or il reste que le

GC doit sassurer de travailler assez vite en prevision des pires situations p ossibles Dans ce cas

le GC doit nir chaque cycle avant quaucune des zones nait pu manquer despace libre Un tel

GC doit donc travailler b eaucoup plus vite que si lespace libre etait mis en commun Meme si

lecacite nest pas le facteur imp ortant dans nos travaux elle nest a negliger completement

Outre le probleme de son inecacite un GC dans une organisation par zones se devrait

de deplacer les ob jets dans le tas Ceci reste un probleme ardu comme nous en discutons

dans la section sur les GC a un seul espace Cet asp ect combine a la recherche dune facon

acceptable de guider la vitesse du GC nous laisse supp oser quun eventuel GC temps reel p our

cette organisation memoire est probablement fort complexe

Nous navons donc pas trouve par nousmemes de technique raisonnablement simple p ouvant

etre utilisee avec une de ces deux organisations par regroup ement

GC a deux semiespaces

Lorsquun GC a deux semiespaces est utilise le tas est divise en deux moities Cest ce qui

explique le nom du GC Il existe de nombreuses variantes de ce GC autant comme GC blo quants

que comme GC temps reel

Nous commencons par la description sommaire dune version blo quante Nous continuons

avec une version temps reel Nous nous interessons particulierement au GC de Bro oks Bro

Version blo quante

Lorsque le GC ne travaille pas un seul des semiespaces est en utilisation Celui qui est

utilise contient les ob jets du systeme et une certaine quantite despace libre Lallo cation des

nouveaux ob jets se fait aussi dans ce semiespace Lorsquil ne reste plus assez despace libre

p our p ermettre une allo cation le GC est declenche

Le GC copie les ob jets vivants ou accessibles du semiespace utilise a lautre Nous app ellons

FROM le semiespace en cours dutilisation et TO le semiespace qui sapprete a recevoir les

ob jets vivants Les ob jets copies sont places a la queueleuleu dans TO Ainsi lorsque le GC

a termine son travail le role des semiespaces est interchange et le nouveau semiespace utilise

contient un blo c compact dob jet suivi despace libre Les GC a deux semiespaces eectuent un

compactage et previennent la formation de fragmentation

CHAPITRE RECHERCHE DUN GC ADEQUAT

La recherche des ob jets vivants se fait a partir des racines de lapplication Les racines dune

application sont les references toujours presentes Par exemple dans le cas de notre interprete

les racines comprennent les quelques registres de la machine virtuelle et les variables globales du

programme Tout ob jet reference depuis les racines est vivant et est copie dans TO Tout ob jet

reference par un ob jet vivant est copie aussi

Lorsquun ob jet est copie les etapes suivantes sont faites ses champs sont copies dans TO

il est marque un de ses champs est utilise p our indiquer la p osition de la nouvelle version de

lob jet Il est imp ortant de p ouvoir marquer un ob jet an deviter de le copier plus dune fois

De plus lorsque les ob jets copies sont fouilles a la recherche dautres ob jets leurs champs sont

mis a jour an que les references reetent la nouvelle p osition des ob jets Les racines aussi voient

leurs references mises a jour lorsquelles sont fouillees

Il existe de nombreuses facons de parcourir les racines de fouiller les champs des ob jets de

marquer un ob jet et dindiquer la p osition de la nouvelle version dun ob jet Nous nentrons

pas dans les details de chaque methode existante Nous nous contentons de mentionner que

lalgorithme de Cheney Che est un algorithme simple representatif et quil est utilise

couramment

Version temps reel GC de Bro oks

Pour obtenir une version temps reel dun GC a deux semiespaces il ne sut pas que le GC

et lapplication sechangent le controle regulierement En eet durant un cycle le GC mo die

considerablement lapparence des semiespaces et lapplication continue a faire des mutations

sur les ob jets Ces dicultes sont deja exp osees plus haut

An quil puisse etre temps reel le GC ne doit pas etre declenche seulement lorsquil ne

reste plus despace libre dans le semiespace actif Il doit etre declenche longtemps a lavance

ou meme etre continuellement en activite

Plus un GC est declenche a lavance plus il risque detre conservateur Un GC conservateur

est un GC qui conserve des ob jets qui sont morts avant la n du cycle Ces ob jets auraient ete

ramasses par un GC blo quant Le fait detre conservateur est normalement une consequence du

comp ortement temps reel Le conservatisme a un impact sur la quantite dob jets vivants et

morts presents dans le tas et donc sur la quantite de travail quil faut faire a chaque cycle

Toutefois un GC declenche plus longtemps a lavance p eut decouper le travail a faire en plus

p etits morceaux assurant des b ornes plus serrees sur la duree des operations de lapplication La

facon optimale de regler le rythme de travail du GC depend donc de ce que lon privilegie entre

la recherche decacite et la minimisation de la duree des blo quages d us au GC La discussion

des derniers paragraphes tient en fait p our tous les GC temps reel

Etant donne que le GC deplace les ob jets de FROM a TO p endant que lapplication sexe

cute il faut sassurer que cette derniere soit capable de les retrouver rapidement La methode

que nous decrivons ici fait partie de la technique de Bro oks Bro Il sagit da jouter a

CHAPITRE RECHERCHE DUN GC ADEQUAT

tout ob jet un champ supplementaire servant a p ointer sur lob jet luimeme Plus exactement

le champ supplementaire est juste devant lob jet et p ointe sur le premier de ses champs Un

ob jet ne detient pas des references directes aux autres ob jets mais des references a leur champ

supplementaire Les acces a un ob jet doivent toujours passer par son champ supplementaire

Linteret de ce champ est de p ermettre au GC de copier les ob jets de FROM a TO sans

que lapplication ne puisse voir la dierence Ce que le GC a a faire est creer la nouvelle version

de lob jet dans TO faire p ointer le champ supplementaire de la vieille version vers le premier

champ de la nouvelle version Ainsi que lapplication accede a lob jet via une reference mise

a jour ou via une vieille reference elle ab outit au meme ob jet grace a la double indirection

Eventuellement le GC parvient a copier tous les ob jets vivants et mettre a jour toutes les

references Le semiespace TO devient le semiespace actif et ce jusqua ce quun nouveau cycle

commence

Le champ supplementaire p ermet du meme coup dindiquer le marquage Un ob jet marque

est un ob jet dont le champ supplementaire ne p ointe pas sur le champ suivant Lorsquun ob jet

est marque cest son champ supplementaire qui indique la p osition de sa nouvelle version

Nous arretons la les explications sur les GC temps reel a deux semiespaces Nous avons

insiste sur lidee du champ supplementaire car il nous a servi dinspiration p our la creation de

la technique que nous decrivons plus loin

Interet des GC a deux semiespaces

Parmi les avantages des GC a deux semiespaces nous p ouvons mentionner le compactage

leur relative simplicite et leur ecacite Ils sont probablement parmi les plus ecaces du moins

parmi les GC qui deplacent les ob jets Il existe des GC passablement plus ecaces mais ils

laissent les ob jets sur place p ermettant a la fragmentation de sinstaller

Les GC a deux semiespaces ont le desavantage de demander deux semiespaces et de ne

p ouvoir sto cker des ob jets que dans un seul a la fois ou dans lequivalent dun seul dans le

cas des GC temps reel Dune certaine facon chaque ob jet prend deux fois lespace quil a lair

do ccup er

Ce probleme nexiste pas avec les GC travaillant sur un seul espace Une technique a un

espace qui demande daugmenter legerement la taille des ob jets par rapp ort a une technique a

deux semiespaces p ermet malgre tout datteindre une plus grande compacite

Un GC temps reel a deux semiespaces est implante dans une des versions de notre interprete

Il ne sagit pas exactement de la technique de Bro oks Le marquage et le lien a la nouvelle version

dun ob jet sont faits dieremment Dans cette version le typage est fait de facon uniforme donc

les ob jets disp osent tous dun champ de type et nous utilisons ce champ p our faire le marquage

Lapplication doit verier a chaque acces si lob jet est une vieille version Si cest le cas le lien

a la nouvelle version se trouve dans le premier champ ordinaire

CHAPITRE RECHERCHE DUN GC ADEQUAT

Cette version de linterprete nous a p ermis de nous familiariser avec le controle du rythme

de travail du GC Cette tache etant plus simple dans un GC a deux semiespaces que dans le

GC que nous avons adopte par la suite Nous navons malheureusement pas de comparaisons

empiriques sur la consommation de memoire des deux techniques La representation des types

par taggage est adoptee entre ces versions

GC a un seul espace

Parmi les GC a un seul espace il y a deux grandes familles les GC mark sweep et les GC

compactants mark compact

Les GC mark sweep fonctionnent en identiant tous les ob jets vivants et en convertissant

les ob jets morts en espace libre Les ob jets ayant survecus ne sont pas deplaces Ce type de GC

nelimine donc pas la fragmentation Ils sont p eu interessants dans le cadre de linterprete

Les GC compactants quant a eux identient les ob jets vivants et les regroup ent a un b out

du tas Il existe diverses strategies p our eectuer le regroup ement Des GC deplacent certains

des ob jets vers les trous dans les adresses plus basses Dans ce cas le regroup ement nest pas

necessairement parfaitement compact et p eut avoir un comp ortement en pire cas qui est assez

grave Pour etre acceptable une telle technique devrait p ouvoir garantir une p erte despace

b ornee et assez reduite

Dautres GC sassurent que les adresses basses sont completement o ccupees La methode qui

est souvent utilisee p our parvenir a cette n consiste a faire glisser les ob jets vivants vers les

adresses basses Il sagit de rechercher lineairement les ob jets marques et de les deplacer a la

suite du precedent ob jet vivant

Les GC compactants p our lesquels nous avons une description sont tous des GC blo quants

Ils consistent en une phase de marquage o u les ob jets accessibles sont tous marques suivie par

une phase o u le deplacement des ob jets et la mise a jour des references sont eectues de facon

plus ou moins conjointe

La mise a jour des references p eut se faire de dierentes facons Par exemple lalgorithme de

Morris Mor fait deux passes dans les ob jets Dans la premiere passe les references p ointant

vers des adresses plus basses sont mises a jour Dans la seconde les references p ointant vers des

adresses plus hautes sont mises a jour et les ob jets sont deplaces vers leur nouvelle p osition

Lidee consiste a chaner ensemble les ob jets p ointant vers chaque ob jet Une fois parvenu a un

ob jet sa p osition nale p eut etre calculee et tous les ob jets le p ointant sont mis a jour

La realisationdun GC temps reel compactant p ose des problemes plus serieux quant a la mise

a jour des p ointeurs Lorsquun ob jet est deplace on sait quil nest pas p ossible de mettre a jour

toutes les references le designant dans un temps raisonnablement court Il est donc inevitable

que lapplication reprenne le controle de lexecution avant que toutes les references a lob jet

soient mises a jour Il devient necessaire de laisser une information quelconque p ermettant a

CHAPITRE RECHERCHE DUN GC ADEQUAT

lapplication de retrouver la nouvelle version de lob jet

Une des premieres idees qui p euvent venir a lesprit consiste a dire quun des champs de la

vieille version de lob jet devrait servir a p ointer vers la nouvelle version De cette facon lors dun

acces a un ob jet lapplication verie sil a ete deplace et si oui suit le p ointeur a la nouvelle

version Comme il p eut rester des liens a la vieille version jusqua la n du cycle du GC celleci

doit rester en place jusqua la n Il y a alors un probleme la vieille version risque de se trouver

sur un emplacement o u la nouvelle version dun autre ob jet doit etre installee

Une des facons de regler ce probleme consiste a faire en sorte que les nouvelles versions

ne puissent etre installees aux memes emplacements que les vieilles versions On p eut donc

programmer le GC p our quil compacte vers les adresses basses et hautes alternativement Il

faut alors sassurer que les ob jets deplaces nempietent pas sur la partie des ob jets p ossiblement

a deplacer Finalement cette operation revient a faire une division du tas en deux semiespaces

Nous avons developpe une autre technique p our parvenir a realiser un GC temps reel com

pactant a un espace Elle est inspiree de la technique de Bro oks en ce qui concerne lutilisation

systematique dun champ supplementaire p our acceder a un ob jet Une mo dication de ce champ

fait implicitement suivre toutes les references a cet ob jet Dans notre technique ces champs sont

tous regroupes a un b out du tas De plus un tel champ est assigne a un ob jet p our toute sa

duree de vie

La technique que nous presentons ici a ete publiee dans une conference voir DFS Nous

reprenons les explications presque completement dans le reste du chapitre

Nous commencons par decrire une version non temps reel de la technique Ensuite nous

decrivons les a jouts a y faire p our la rendre temps reel Les asp ects du traitement des longs

ob jets et du reglage de la vitesse du GC que nous navons queeures jusquici y sont ab ordes

en profondeur Cette technique est plus compacte que toutes celles que nous avons trouvees dans

la litterature et elle est utilisee dans les dernieres versions de linterprete

La version blo quante de notre technique de GC

Avant de decrire de quelle facon le GC recupere de lespace dans le tas il imp orte de presenter

lorganisation du tas Ensuite les conditions necessaires au declenchement du GC ainsi que la

technique de recuperation sont decrites

Disp osition du tas

Nous supp osons au depart que le tas est divise en deux regions celle des identicateurs et celle

des ob jets et de la pile de marquage La taille des regions ne doit pas etre choisie arbitrairement

comme on le verra un p eu plus loin

CHAPITRE RECHERCHE DUN GC ADEQUAT

Un identicateur sert de p ointeur vers un ob jet dans la deuxieme region Generalement les

identicateurs ne sont pas tous utilises Les identicateurs inutilises sont chanes en une liste

didenticateurs libres Lidenticateur assigne a un ob jet demeure le meme durant toute la vie de

lob jet La region des identicateurs nest pas compactee Mais comme tous les identicateurs

ont la meme taille ceci ne cause pas de fragmentation mais simplement une disp ersion des

identicateurs vivants

La region des ob jets et de la pile de marquage ne comp orte pas de separation xe entre

ses deux parties Les ob jets sont places un a la suite de lautre a partir des adresses basses

Lespace reserve p our la pile grossit a partir des adresses hautes Chaque ob jet a un champ

supplementaire qui sert a contenir ladresse de son identicateur Nous app elons ce champ le

p ointeur arriere On verra a la section lutilite de la pile de marquage

Lors de lallo cation dun ob jet un identicateur est reserve dans la premiere region lespace

necessaire est reserve dans la deuxieme region les champs de lob jet sont initialises lidentica

teur recoit ladresse du nouvel ob jet et ladresse de lidenticateur est retournee a lapplication

Lespace reserve dans la deuxieme region est constitue des champs de lob jet incluant son p oin

teur arriere et dune case memoire p our la pile Lapplication doit toujours acceder aux champs

de lob jet via lidenticateur

La pile nest utilisee que durant la phase de marquage mais un espace a son eet est reserve

en p ermanence Nous jugeons quil est preferable que le GC gere luimeme une pile p our le

marquage Premierement la pile dexecution de lapplication risque de ne pas etre assez grande

p our p ermettre de marquer recursivement tous les ob jets dune structure de donnees tres pro

fonde Deuxiemement les informations sto ckees par le GC dans sa propre pile sont b eaucoup

plus compactes que celles sto ckees dans la pile dexecution

La gure montre un exemple o u le tas ne contient que deux paires Cellesci forment la

liste On p eut remarquer que le premier champ de chaque paire est le p ointeur arriere

vers leur identicateur resp ectif A lextreme droite du tas se trouvent les deux cases reservees

p our la pile On p eut voir aussi que les identicateurs qui ne sont pas utilises forment une liste

didenticateurs libres A chaque allo cation les p ointeurs dallo cation et de pile se rappro chent

lun de lautre

Declenchement du GC

Le GC doit etre declenche lorsque lapplication demande lallo cation dun ob jet p our lequel

il ne reste plus assez despace Il nest pas necessaire de verier sil reste un identicateur libre

si lon xe une taille susamment grande p our la region des identicateurs En eet supp osons

que le plus p etit ob jet alloue nait quun champ Alors lors de lallo cation dun tel ob jet on

reserve un identicateur un p ointeur arriere le champ et une case p our la pile Ce type dob jet

etant le plus p etit on sait quau maximum le quart du tas sera o ccupe par des identicateurs

Donc en prenant la region des identicateurs trois fois plus p etite que celle des ob jets on elimine

ce test Il ne reste que le test p our verier sil y a assez despace p our lob jet dans la deuxieme

CHAPITRE RECHERCHE DUN GC ADEQUAT

/ 1 2 / ...

libre alloc_obj alloc_pile

racine

Legende racine une racine de lapplication

libre la tete de la liste des identicateurs libres

allo c ob j le p ointeur dallo cation des ob jets

pile debut de la zone reservee p our la pile allo c

Fig Il lustration du tas contenant la liste

region

Dans la version nale de linterprete nous nous sommes assures que tous les ob jets qui sont

alloues ont au moins deux champs Pour parvenir a ce minimum de champs nous a joutons un

champ articiel aux vecteurs et aux chanes vides Ces ob jets ne sont pas necessairement tres

utilises donc lespace p erdu est minime en moyenne Toutefois ceci nous p ermet de reduire la

region des identicateurs a un cinquieme du tas

Description de lalgorithme

Le marquage

La premiere phase du GC est le marquage Lalgorithme commence par marquer tous les

ob jets accessibles directement des racines Le fait de marquer un ob jet cause son a jout dans la

pile de marquage Les ob jets qui sont sur la pile sont des ob jets dont on dira quils nont pas

encore ete fouilles a la recherche de references a des ob jets non encore marques Par la suite

lalgorithme extrait un ob jet de la pile le fouille et marque tous les ob jets nouvellement atteints

Le pro cessus de marquage se p oursuit tant que la pile nest pas vide

Connaissant la facon de marquer on p eut comprendre p ourquoi nous avons choisi de reserver

une case de pile par ob jet alloue En eet il est p ossible que toute la pile sauf une case soit

utilisee Par exemple un vecteur qui contient des references sur tous les autres ob jets du tas est

une structure de donnees qui fait en sorte que la pile est utilisee presque completement

Nous utilisons une astuce simple et relativement p ortable p our eviter de reserver de lespace

supplementaire p our le bit de marquage Il est raisonnable de supp oser que les mots de la machine

sont a des adresses paires en particulier les identicateurs On p eut donc utiliser le bit le moins

signicatif du p ointeur arriere comme bit de marquage Il serait egalement p ossible dutiliser le

bit le moins signicatif de lidenticateur mais cela serait moins ecace p our les deux raisons

CHAPITRE RECHERCHE DUN GC ADEQUAT

suivantes lors du compactage le test du bit de marque demanderait une reference de plus a la

memoire les acces ordinaires aux champs de lob jet demanderaient de masquer le dernier bit de

lidenticateur

Le compactage

La deuxieme phase du GC est le compactage Les ob jets marques sont regroupes au debut

du tas comme sils avaient tous glisse vers les adresses basses Leur ordre est donc preserve

Deux p ointeurs partent du debut de la region des ob jets Le premier est le p ointeur de source

et sert a rechercher les ob jets marques Le second est le p ointeur de destination et indique la

nouvelle p osition de chaque ob jet marque Si lob jet p ointe par le p ointeur source est marque il

est deplace a lendroit p ointe par le p ointeur de destination De plus son identicateur est mis

a jour p our quil p ointe vers la nouvelle p osition de lob jet Bien s ur lidenticateur de lob jet

est retrouve rapidement grace au p ointeur arriere Si lob jet nest pas marque son identicateur

est libere et a joute a la liste des identicateurs libres Durant le compactage les ob jets vivants

sont comptes an de p ouvoir reserver la b onne taille de pile p our le pro chain cycle de GC et de

mesurer correctement la quantite de memoire libre

La technique temps reel

Nous decrivons tout dab ord les barrieres en lecture et en ecriture qui doivent etre a joutees

a la technique de base ensuite nous montrons de quelle facon lalgorithme du GC est decoupe

nous parlons de lasp ect synchronisation entre le GC et lapplication enn nous decrivons trois

ameliorations p ouvant etre app ortees au GC

Il y a certaines contraintes qui doivent etre imp osees a lapplication en plus des barrieres p our

que cette technique telle nous allons la decrire puisse fonctionner Premierement le nombre de

racines de lapplication doit etre assez p etit Deuxiemement lapplication ne doit pas tenter de

conserver plus quune certaine fraction du tas en ob jets vivants Cette derniere contrainte est

commune a toutes les techniques de GC temps reel a lexception du comptage de references

Les barrieres en lecture et en ecriture

Lindirection via lidenticateur

La barriere la plus imp ortante est deja incluse dans la technique de base cest lutilisation

des identicateurs En eet ces identicateurs p ermettent au GC de deplacer un ob jet et de

faire suivre toutes les references a cet ob jet en une seule aectation donc de facon atomique

CHAPITRE RECHERCHE DUN GC ADEQUAT

Barriere en ecriture

Nous utilisons une barriere en ecriture durant le marquage p our eviter que le GC ne collecte

des ob jets accessibles A linstant o u un ob jet A non marque est sto cke dans un ob jet B deja

marque A est luimeme marque Cette barriere en ecriture est similaire a celle prop osee dans

DLM et est app elee barriere en ecriture a mise a jour incrementielle incremental update

write barrier Cette barriere est moins conservatrice quune barriere en lecture Bak Bro

Nil Bak NS qui ne laisse acceder lapplication a aucun ob jet non marque ou quune

barriere en ecriture de type snapshotatbeginning Yua qui conserve tout ob jet ayant ete

accessible au debut du cycle de GC Il y a une autre barriere en ecriture de type incremental

update qui est decrite dans Ste Laction de cette barriere consiste a noter que lob jet deja

fouille qui vient de recevoir lob jet non marque devra etre fouille a nouveau ulterieurement

Cette barriere est encore moins conservatrice que celle que nous avons adoptee Wil mais

elle est plus dicile a implanter

Barriere p our les longs ob jets

Il y a une derniere barriere en lecture et en ecriture qui doit etre en place p our les longs

ob jets La denition de long ob jet p eut varier dune implantation a lautre Dans notre

interprete ce sont les vecteurs et les chanes de caracteres qui sont consideres comme de longs

ob jets Lorsquun long ob jet est en cours de copie le debut de lob jet se trouve a la nouvelle

p osition et le reste se trouve a la p osition originale Durant un tel copiage le GC declare

lidenticateur du long ob jet cestadire que lidenticateur est mis dans une variable globale

Ainsi lapplication p eut verier quel ob jet le GC est en train de deplacer La barriere consiste

simplement a comparer lidenticateur de lob jet accede a celui qui est declare En cas degalite

il faut verier dans laquelle des deux parties se trouve le champ qui doit etre accede

Lalgorithme du GC

La banque de temps

Avant de decrire lalgorithme du GC il est imp ortant de parler de la banque de temps du GC

Lidee consiste a maintenir un compteur qui indique la quantite de travail que p eut eectuer le

GC A chaque allo cation une certaine quantite de temps est a joutee a la banque le GC travaille

tant que sa banque est p ositive et ensuite lob jet demande est reellement alloue Nous verrons

dans la pro chaine soussection comment le temps est gere lors des allo cations et lors du travail

du GC

Les operations avec un asterisque sont des operations qui co utent du temps au GC cesta

dire qui enlevent du temps de sa banque

CHAPITRE RECHERCHE DUN GC ADEQUAT

Lalgorithme proprement dit

Lalgorithme est decrit a la facon dun automate ni Cest a chaque transition quun test

est fait p our verier que la banque de temps nest pas epuisee Letat initial est letat

Preparer le cycle du GC Declarer a lapplication que le GC est en phase de marquage

Aller a

Sil ny a pas dob jet sur la pile de marquage aller a Si lob jet a fouiller est long aller



a Sinon fouiller lob jet et aller a



Fouiller autant de champs que p ossible dans lob jet Sil a ete fouille au complet aller a

Sinon aller a

Marquer les ob jets directement accessibles depuis les racines Si la pile est vide aller a

Sinon aller a

Fin du marquage Debut du compactage Aller a

Sil ny a plus dob jets a deplacer aller a Sinon aller a



Si lob jet nest pas marque liberer son identicateur sauter pardessus lob jet et aller



a Si lob jet est p etit le deplacer changer la valeur de son identicateur et aller a



Sinon changer la valeur de son identicateur declarer que lob jet est en deplacement et

aller a



Deplacer autant de cases de lob jet que p ossible Mettre a jour le p oint de coupure declare

a lapplication Si lob jet est completement deplace cesser de le declarer coupe et aller a

Sinon aller a

Clore le cycle du GC Aller a

Observations

Lalgorithme necessite en plus un test special lorsque le tas est vide En eet il ne co ute

aucun temps au GC p our faire un cycle sur un tas vide Un moyen simple deviter le test consiste

a introduire un ob jet toujours vivant dans le tas des son initialisation

Letat qui fouille les racines p eut etre atteint plus dune fois par cycle Ceci est necessaire a

cause du fait que des allo cations et des changements dans les racines se font lors des pauses du

marquage De plus il est necessaire de fouiller toutes les racines dun coup Sinon il nest pas

p ossible de savoir sil ny a vraiment plus dob jets a marquer Ceci explique p ourquoi il faut que

lapplication nait quun p etit nombre de racines Malgre les allo cations faites par lapplication

durant le marquage le rythme de marquage du GC est regle de facon a assurer la terminaison

du marquage

CHAPITRE RECHERCHE DUN GC ADEQUAT

Il est p ossible deliminer la limite sur le nombre de racines Nous en parlerons dans les

ameliorations qui p euvent etre app ortees a la technique

Nous avons prefere que cette fouille des racines soit atomique et ne co ute aucun temps au

GC Nous aurions pu considerer que cette operation avait un co ut Auquel cas nous aurions

un controle plus serre sur les b ornes de temps dexecution mais aussi lanalyse du rythme de

travail du GC serait plus complexe p our lanalyse voir plus loin

Pour ce qui est du compactage les mo dications dans la version temps reel sont assez simples

La encore le rythme de compactage est susamment eleve p our p ermettre au p ointeur de source

de rejoindre le p ointeur dallo cation A la n du compactage le p ointeur dallo cation est mo die

p our indiquer la meme p osition que le p ointeur de destination

An que le GC ne conserve pas trop dob jets inaccessibles nous avons choisi dallouer les

ob jets non marques p endant le marquage Ceci laisse une chance aux ob jets de courte duree de

devenir inaccessibles avant que le GC ne les marque Par exemple un group e dob jets frachement

alloues p eut etre detenu temp orairement par une racine et abandonne ensuite Si les racines ne

sont pas fouillees durant ce temps ces ob jets risquent de ne jamais etre atteints par le marquage

Durant le compactage toutefois les ob jets doivent etre alloues marques etant donne que le GC

ne p eut avoir aucune preuve quil sont devenus inaccessibles avant davoir fait un nouveau

marquage

Synchronisation du GC avec lapplication

Contrainte sur la quantite dob jets vivants

A tout moment lapplication ne doit pas tenter de conserver plus quune certaine fraction du

tas en ob jets accessibles En fait plus le tas contient dob jets accessibles plus le temps en pire

cas pris par les operations primitives est grand Si on calcule p our lapplication le p ourcentage

do ccupation maximale du tas en ob jets alloues accessibles on p eut alors calculer les b ornes de

temps sur chaque operation primitive

Comptabilite du temps du GC

La facon de compter le temps lors des allo cations et du travail du GC a une grande imp ortance

p our assurer un b on fonctionnement du GC La vitesse du GC est reglee par un parametre que

nous app elons le ratio A chaque allo cation nous a joutons a la banque de temps du GC le

pro duit entre le ratio et lespace demande p our le sto ckage de lob jet Nous avons decide que

lespace qui compterait serait celui requis par les champs de lob jet le p ointeur arriere et la case

reservee p our la pile Bref cest lespace qui est consomme par un ob jet dans la region des ob jets

et de la pile de marquage De facon analogue le temps qui est requis p our fouil ler un ob jet et

non pas p our le marquer est lespace pris par cet ob jet dans la region en question Pareillement

p our le traitement dun ob jet durant la phase de compactage Que lob jet soit accessible ou non

CHAPITRE RECHERCHE DUN GC ADEQUAT

son traitement consomme une quantite de temps egale a lespace quil o ccup e dans la region des

ob jets Nous ne comptons pas lespace pris par lidenticateur etant donne que nous supp osons

que le nombre didenticateurs a ete choisi de facon a ce quils ne puissent etre epuises du

moins sans epuisement de lespace dans la region des ob jets

Cette comptabilite du temps a ete adoptee parce quelle simplie b eaucoup le calcul du ratio

En eet le ratio indique dune certaine facon combien de cases memoire doivent etre traitees

p our chaque case allouee Plus un ob jet a allouer est long plus il consomme de lespace libre et

plus il fournit de temps au GC lors de son allo cation Cette comptabilite concorde avec le critere

sur les b ornes de temps des operations elementaires imp ose a un GC temps reel Le critere est

enonce a la section

Ainsi il est simple de compter combien dunites de temps il faut p our la phase de compactage

Chaque ob jet doit etre traite une et une seule fois Lensemble des ob jets a traiter est constitue

de ceux existant au debut du cycle du GC ceux alloues durant le marquage et ceux alloues

durant le compactage Le temps requis p our cette phase est donc lespace quo ccup eront ces

ob jets a la n de la phase On p eut calculer aussi combien dunites de temps sont requises par

le marquage Chaque ob jet doit etre traite fouille au plus une fois Lensemble des ob jets qui

sont p ossiblement a considerer est constitue de ceux qui existaient au debut du cycle plus ceux

qui ont ete alloues durant le marquage

Calcul du ratio

Nous allons maintenant expliquer la facon de calculer le ratio Il est imp ortant de noter

que le temps requis p our faire le marquage ne p eut etre plus long que celui requis p our faire

le compactage Aussi il faut rapp eler que lapplication ne doit jamais conserver plus quune

certaine fraction du tas en ob jets vivants Soit la fraction maximale o ccupee

par les ob jets vivants Nous allons montrer que si nous choisissons un ratio R egal a

lo ccupation du tas au debut de chaque cycle sera au maximum

Preuve par induction Base Au depart le tas est completement vide donc lo ccupation du

tas est au plus Pas Il faut dab ord montrer que le cycle du GC aura eu le temps de se

terminer avant que lespace libre ne se soit epuise Par hypothese dinduction au maximum

du tas est o ccupe au debut du cycle Soit v v la fraction du tas o ccupee par les ob jets

la fraction du tas o ccupee par les ob jets morts Par abus de vivants et m v m

langage nous parlons de lo ccupation du tas mais en fait cest de lo ccupation de la region

du tas est libre Apres des ob jets dont nous parlons reellement Clairement au moins

du tas nous pretendons que le GC a recu assez de temps p our completer lallo cation de

du tas grace au ratio le GC a recu du temps p our traiter son cycle Apres lallo cation de

du tas Le temps sera distribue en p our le marquage et p our le compactage

Le temps requis en pire cas p our le marquage est celui demande si tous les ob jets vivants

au debut sont marques et tous les ob jets alloues durant le marquage sont marques Comme le

marquage nest jamais plus long que le compactage au plus du tas est alloue durant le

CHAPITRE RECHERCHE DUN GC ADEQUAT

marquage Le temps en pire cas requis par le marquage est donc v

Le temps requis en pire cas p our le compactage est celui demande p our traiter tous les ob jets

existants au debut et tous les ob jets alloues durant le cycle Ce qui represente un temps en pire

cas de v m Le cycle du GC p eut se terminer avant que lespace libre ne soit epuise

Du moins p our ce cycle

Il reste a montrer qua la n de ce cycle il y aura au maximum du tas qui sera o ccupe

En pire cas les ob jets qui p euvent survivre au cycle sont ceux qui etaient vivants au debut et

ont ete alloues durant le cycle ceux alloues durant le cycle Il y en avait v au debut Au plus

Ce qui termine la Donc lo ccupation au debut du pro chain cycle sera au plus v

preuve

Bien entendu dans une implantation concrete il est preferable de choisir un ratio entier Il

sut de prendre le plus p etit entier superieur ou egal a

Trois ameliorations

Il est certain quun GC temps reel imp ose une penalite sur la p erformance globale dun sys

teme Nous commencons par prop oser deux ameliorations qui p ermettent daccrotre lecacite

du GC

La premiere est une amelioration p our reduire le temps pris par le compactage Normalement

un ob jet alloue durant le compactage lest a la p osition du p ointeur dallo cation a la suite du

dernier ob jet alloue De plus il est alloue marque Et eventuellement le p ointeur de source

du compactage parvient a cet ob jet et le deplace a sa nouvelle p osition La o u on p eut faire

une economie cest lorsquil y a assez despace entre le p ointeur de source et le p ointeur de

destination p our loger lob jet En lallouant immediatement parmi les ob jets deplaces on evite

de le deplacer inutilement La gure illustre cette amelioration Au lieu dallouer lob jet

marque en noir a lendroit p ointe par al loc il est alloue non marque en blanc a lendroit

p ointe par dest

Leet de cette premiere amelioration est de faire terminer les cycles de GC plus tot Ce qui

p ermet en general davoir une o ccupation du tas moins grande a la n de chaque cycle Pour

que cette amelioration soit protable il faut implanter aussi la suivante retarder le lancement

du cycle si le tas nest pas encore assez plein Comme on a vu a la soussection precedente

le ratio R est calcule de facon a ce quil assure un b on fonctionnement du GC etant donnee

une o ccupation initiale p ouvant aller jusqua Donc il est inutile de declencher le nouveau

cycle tant que lo ccupation est sous ce seuil La technique p our regler le depart du GC consiste

simplement a enlever de la banque de temps du GC la b onne quantite Par exemple sil reste

en espace libre avant datteindre le seuil o u le GC doit obligatoirement se declencher on

enleve R de sa banque de temps Cette derniere amelioration ne necessite pas que la premiere

amelioration soit implantee

CHAPITRE RECHERCHE DUN GC ADEQUAT

.....libre...... libre......

(a) dest source alloc

.....libre...... X ...... libre......

(b) dest source alloc

X ...... libre......

(c) dest source alloc

Fig Objet al loue immediatement parmi les objets deplaces durant le compactage

a Etat original du tas

b Allo cation de X de la facon habituelle

c Allo cation de X directement parmi les ob jets deplaces

La troisieme amelioration a app orter consiste a enlever la contrainte exigeant quil y ait un

p etit nombre de racines dans lapplication On p eut avoir un nombre non b orne de racines et

les fouiller de facon incrementielle Toutefois ceci necessite la mise en place dune barriere en

ecriture sur les racines La barriere consiste a marquer si necessaire lob jet qui est sto cke lors

dune ecriture dans une racine Cestadire quelle fonctionne comme si les racines etaient les

champs dun ob jet deja marque et fouille Toute application qui utilise une pile ou un grand

nombre de variables globales risque davoir a prendre une telle mesure

Dans le cas des dernieres versions de notre interprete nous devons implanter cette amelio

ration a cause du fait que toutes les variables globales du programme Scheme sont rassemblees

dans un tableau et elles p euvent ainsi introduire une quantite non b ornee de racines Ce ne

sont toutefois que les variables globales du programme Scheme qui sont fouillees de facon incre

mentielle Les quelques variables de travail du noyau sont trop p eu nombreuses et trop souvent

mo diees p our etre traitees de cette facon Elles continuent detre traitees de la facon decrite a

la section

An que la fouille des racines soit incrementielle il imp orte dasso cier un co ut a leur fouille

Comme cette operation est faite au debut du marquage cest a cette phase que le travail est

a joute An de ne pas briser linvariant que le compactage nest jamais plus court que le mar

quage on doit a jouter articiellement un temps equivalent a la phase de compactage Cest

adire que dans le calcul du ratio on doit considerer que le marquage est plus long ce qui est

naturel et que le compactage est allonge de facon equivalente ce qui est articiel meme sil

ny a pas plus de travail a faire dans cette phase

Bien que les deux premieres ameliorations ne soient pas strictement necessaires nous les

implantons ainsi que la troisieme qui elle est necessaire

CHAPITRE RECHERCHE DUN GC ADEQUAT

Le calcul du ratio utilise par linterprete

An de garantir que le GC ne cause pas de pauses ind ument longues il faut calculer le ratio

de la facon que nous avons decrite Toutefois p our parvenir a calculer ce ratio il faut determiner

la fraction maximale du tas qui p eut etre o ccupee par des ob jets vivants Ceci demande de faire

une estimation de cette fraction a chaque fois quun programme Scheme est pretraite p our etre

envoye dans le microcontroleur Bien s ur lestimation ne p eut etre faite automatiquement Il

faudrait le concours du programmeur an quil determine des b ornes superieures sur lutilisation

des ob jets de chaque type du nombre de variables globales presentes la quantite de chacune

des fermetures p ouvant etre creees etc En bref il sagit de nombreuses statistiques a obtenir

Bien quil soit p ossible de demander ces statistiques au programmeur nous optons p our une

appro che plus simple Le GC calcule un ratio a chaque cycle Etant donnee lo ccupation du tas au

debut du cycle en ob jets vivants et morts il calcule le ratio qui lui p ermet de terminer son cycle

avant lepuisement de lespace libre Ainsi aucune collab oration nest exigee p our le controle de

la vitesse du GC En pratique le GC choisit un ratio relativement stable comme nous avons

pu le constater en faisant plusieurs tests Ceci a condition que le programme Scheme ne tente

pas de conserver plus quune certaine quantite dob jets vivants bien entendu En theorie nous

croyons quil est p ossible que le ratio ait a monter arbitrairement haut si les circonstances sont

parfaitement defavorables En revanche nous croyons aussi que de telles circonstances sont tres

improbables

Une facon de trouver la fraction du tas o ccupee en ob jets vivants sans demander daide trop

imp ortante du programmeur serait de creer un simulateur Le programmeur ferait fonctionner

son programme en le soumettant aux conditions qui devraient maximiser la conservation dob jets

par son programme Le simulateur fournirait une mesure de lo ccupation memoire a la n de la

simulation Toutefois la qualite des chires deprendrait de la qualite des conditions imp osees lors

de linterpretation du programme Les resultats du simulateur ne p ourrait pas servir a prouver

quun ratio donne est adequat Nous navons pas cree de tel simulateur etant donne que ce nest

pas un outil infaillible et que le calcul du ratio a chaque cycle est une technique qui fonctionne

deja bien en pratique

CHAPITRE COMPILATION VERS DU CODEOCTETS

Chapitre

Compilation vers du co deo ctets

Les dernieres versions de linterprete ne sont pas interactives Ceci vient du fait que la

programmation du microcontroleur ne change pas p our une application donnee On p eut donc

utiliser un compilateur p our transformer le programme Scheme an de pro duire un executable

a installer dans la memoire du microcontroleur

La premiere section presente un ap ercu de lorganisation du systeme en insistant sur le

compilateur Les autres sections ab ordent les dierents asp ects du pro cessus de compilation

Ap ercu du systeme

Le systeme entier

La gure resume les etapes de la construction dun executable p our le microcontroleur a

partir dun programme Scheme Le langage dimplantation de linterprete de co deo ctets est le

C Lassembleur serait preferable au C si lon voulait faire un pro duit ni avec le systeme Pour

notre travail une implantation en C est susante En eet nous disp osons dun compilateur C

qui genere des executables p our le microcontroleur que nous utilisons De plus une implantation

en C p eut etre testee facilement sur une station de travail contrairement a une implantation en

assembleur du HC

lib.scm noyau.c

compilateur compilateur '

prog.scm vers du c-o prog.c C executable

Fig Production dun executable pour microcontroleur a partir du programme progscm

CHAPITRE COMPILATION VERS DU CODEOCTETS

Dans ce systeme compile la compilation nest pas obligatoirement faite sur le microcontro

leur Il est meme b eaucoup plus simple de leectuer sur un ordinateur de plus grande puissance

La compilation seectue en deux etapes traduire le source Scheme en un chier C

ce chier avec linterprete de co deo ctets le noyau p our pro duire lexecutable p our le micro

controleur Un chier contenant une partie des fonctions de la librairie libscm est utilise

lors de la compilation de Scheme vers C Nous avons ecrit nousmemes le compilateur vers du

co deo ctets en Scheme Scheme est un choix interessant p our lecriture de ce compilateur car il

est facile de manipuler un programme Scheme sous forme de donnees Scheme Le compilateur C

est une version disp onible publiquement Nous parlons plus longuement de ce compilateur dans

le chapitre sur les resultats experimentaux section

Le chier C pro duit par le compilateur Scheme contient des declarations decrivant comple

tement le programme source et les fonctions de la librairie qui sont necessaires Un exemple de

chier de sortie est donne en app endice voir section A Les declarations sont les suivantes Il y

a un tableau do ctets et sa longueur celuici constitue le co deo ctets a executer Il y a le nombre

de variables globales et une description de leur valeur initiale Il ne sagit que dune description

et non de la representation des valeurs initiales Les descriptions sont inscrites directement dans

le tableau C qui doit contenir la valeur des variables globales Enn un second tableau do ctets

et sa longueur donnent une description des constantes litterales du source

Le noyau contient tout ce qui est necessaire a linterpretation des informations pro duites pas

le compilateur Premierement il y a bien s ur la machine virtuelle interpretant le co deo ctets

Deuxiemement plusieurs fonctions Scheme de base y sont implantees comme cons vectorref

etc Troisiemement un systeme de gestion memoire so ccup e de lallo cation et de la recuperation

des ob jets Le GC utilise est base sur la technique decrite au chapitre precedent Enn une phase

dinitialisation so ccup e de preparer les registres le tas les variables et les donnees avant le debut

de linterpretation

Le compilateur

Pour pro duire le chier C en sortie le compilateur eectue les etapes decrites cibas Les

etapes sont decrites en detail dans les sections qui suivent

Le programme source est lu

Les formes de syntaxe derivees sont ramenees aux formes de base Le programme resultant

a le meme comp ortement que loriginal

Les expressions sont transformees en arbres de syntaxe Chaque no eud dun arbre a un

type qui corresp ond a une des formes de syntaxe primitives Plusieurs types de no euds ont

des champs supplementaires servant a contenir des attributs calcules par la suite

Le programme est traverse an de connatre lensemble des fonctions de la librairie dont

il a b esoin p our fonctionner

CHAPITRE COMPILATION VERS DU CODEOCTETS

Les taches suivantes sont eectuees lors dune traversee du programme et des fonctions de

la librairie

Extraire les constantes litterales

Trouver la p osition de chaque variable que ce soit dans lenvironnement global ou

dans lenvironnement lexical

Detecter les variables globales mutables

Dans chaque fonction compter les parametresformels et indiquer sil y a un parametre

reste

La valeur initiale des variables globales de la librairie est determinee

Les deux taches suivantes sont eectuees lors dune nouvelle traversee du programme et

des fonctions de la librairie

Decouvrir statiquement le resultat dune reference de variable lorsque cest p ossible

Remplacer lapp el dune fonction complexe par lapp el dune fonction plus simple

lorsque cest p ossible Par exemple un app el a la fonction append p eut etre remplace

par un app el a la fonction interne append qui est specialise p our deux arguments

La p osition de chaque variable globale est xee

Le co deo ctets est genere

La description des constantes litterales est generee

La description de la valeur initiale des variables globales est generee

Les dierentes parties du compilateur sont decrites dans les sections suivantes mais pas ne

cessairement dans le meme ordre que les etapes enumerees ici Les parties sont plutot regroupees

selon leur fonction La generation du co deo ctets est decrite dans le chapitre suivant qui traite

en profondeur de la machine virtuelle

Reduction des formes syntaxiques derivees

La reduction des expressions du programme source en formes syntaxiques de base p ermet de

diminuer le nombre de formes syntaxiques dierentes dans le programme De cette facon il ne

reste que quelques formes fondamentales a traiter par la suite Ainsi le reste du compilateur est

plus simple et donc moins susceptible de contenir une erreur De plus la machine virtuelle qui

doit interpreter le co deo ctets est elle aussi plus simple

Les formes de base

Avant de decrire les dierentes reductions que nous eectuons sur les expressions il imp orte

de preciser quelles sont les formes de base

CHAPITRE COMPILATION VERS DU CODEOCTETS

Liste des formes syntaxiques de base

Les formes de base que nous avons choisies sont presque les memes que celles decrites dans

le R RS

Les references aux variables

Les constantes

Les app els de fonctions

Les lambdaexpressions ayant une seule expression p our corps

Les conditions expressions if avec ou sans alternative

Les aectations expressions set

Les blo cs dexpressions expressions begin Ceci nest pas une expression primitive dans

le standard

Les denitions de variables globales expressions define Ceci ninclut pas les denitions

lo cales qui p euvent etre faites au debut du corps de certaines formes

Les expressions exprimees sous une des ces formes ne sont pas transformees en dautres

formes plus simples Toutefois certaines sont uniformisees an de simplier leur manipulation

par la suite

Uniformisation des formes de base

Bien que la lambdaexpression soit une de nos formes de base elle se doit de ne contenir

quune seule expression dans son corps Lorsquune lambdaexpression en contient plus quune

elles sont placees dans une forme begin

Les formes begin imbriquees sont aplaties Cette mesure est utile principalement a cause

que la recriture des expressions p eut introduire des formes begin sup erues De plus une forme

begin ne contenant quune seule expression est remplacee par cette expression

Les denitions aussi subissent une uniformisation Le R RS p ermet de denir directement

une variable contenant une fonction avec la notation suivante define hvariablei hformalsi

hb o dyi Dans un tel cas la creation de la variable et de la fonction sont reexprimees separement

On obtient alors une expression comme celleci define hvariablei lambda hformalsi hb o dyi

Lapparence nale des expressions define est toujours semblable a celle des expressions set

En Scheme il est p ossible deectuer des denitions internes au debut du corps dune fonction

ou dune forme de liaison La semantique de ces denitions corresp ond a celle du letrec Une

transformation comme celle montree dans lexemple est eectuee lorsque des denitions internes

CHAPITRE COMPILATION VERS DU CODEOCTETS

se trouvent au debut dun corps Or comme nous le voyons plus loin la reduction des formes

deriveesfait en sorte quun corps nit toujours par etre le corps dune lambdaexpression Ainsi il

sut de faire la detection des denitions internes lors de luniformisation des lambdaexpressions

lambda a lambda a

letrec f lambda x define f x

g lambda x define g x

f a g a f a g a

Un app el a une lambdaexpression sans parametre est remplace par le corps de la lambda

expression Une telle expression est habituellement introduite par la reduction des formes deri

vees

lambda hb o dyi hb o dyi

Les reductions proprement dites

Nous p ouvons maintenant decrire les reductions qui sont faites sur les formes derivees An de

ne pas allourdir inutilement le texte avec trop de descriptions et dexemples de transformations

nous nous limitons aux transformations qui ne sont pas decrites dans le standard ou que nous

eectuons dieremment

La reduction des expressions cond se fait selon les regles decrites dans la section du R RS

sauf dans le cas dune clause htmpi represente une variable dont le nom est unique Elle

ne p eut masquer aucune autre variable

cond htesti hrecipienti

hclause i

let htmpi htesti

if htmpi

hrecipienti htmpi

cond hclause i

La reduction des expressions case nest pas faite comme dans le R RS A nouveau nous

utilisons une variable au nom unique an dobtenir une expression transformee moins grosse

case hkeyi

d hsequencei

let htmpi hkeyi

cond hmemvi htmpi d

CHAPITRE COMPILATION VERS DU CODEOCTETS

hsequencei

Dans notre regle de transformation et dans celle du standard dailleurs il est indique a laide

de hmemvi quune expression sevaluant a la fonction memv doit etre inseree

Il est imp ortant de noter que dans un tel cas il nest pas susant dy mettre la reference

de variable memv Il y a deux b onnes raisons p our cela Premierement lorsque la reduction de

lexpression case est faite on ne sait pas dans quelle autre expression elle se trouve Si elle se

trouve dans une forme de liaison qui a lie la variable memv a une valeur quelconque le resultat

de la reduction ne sera clairement pas equivalent a lexpression originale Deuxiemement meme

si lenvironnement lexical baignant lexpression case ne masque pas la variable memv il nest pas

certain que la variable globale ainsi nommee contienne toujours la fonction memv Les mutations

sont p ermises sur toutes les variables donc la variable memv p eut avoir ete mutee ou redenie

avant le moment o u lexpression case est executee

Notre facon de regler ce probleme consiste a a jouter quelques expressions au debut du pro

gramme Ce sont denitions qui copient sous un autre nom les fonctions comme memv Les

fonctions ainsi protegees sont memv makepromise listvector list append et cons

Comme on le voit un p eu plus loin makepromise sert dans la reduction des formes delay et

les dernieres fonctions de la liste sont utilisees dans la reduction des formes quasiquote Les

denitions copient les fonctions dans des variables dont le nom est unique

La forme and est reduite dune facon un p eu plus simple que celle prop osee par le R RS

La dierence reside dans les cas o u il y a plus dune expression interne La reduction que nous

utilisons est la suivante

and htest i htest i

if htest i and htest i f

La forme or est reduite dune facon plus simple que celle donnee par le standard grace a

lutilisation dune variable au nom unique Il sagit du cas o u il y a plus dune sousexpressions

dans la forme

or htest i htest i

let htmpi htest i

if htmpi

htmpi

or htest i

La reduction des formes let et let est faite selon les regles de transformation du standard

La reduction des formes letrec est faite de facon dierente Elle ne resp ecte pas la semantique

de Scheme mais seulement au niveau de la detection derreurs donc elle est acceptable p our

linterprete La reduction est la suivante Sil ny a aucune variable liee dans une forme letrec

CHAPITRE COMPILATION VERS DU CODEOCTETS

elle est transformee en une forme let Sil y a des variables liees la transformation est la suivante

letrec hvariable i hinit i

hb o dyi

let hvariable i f

set hvariable i hinit i

let

hb o dyi

La forme let sans liaison qui entoure le corps du letrec sert a assurer que deventuelles

denitions au debut de ce corps sont encore au debut dun corps apres la reduction Ce let

articiel est elimine par la suite par le pro cessus duniformisation des app els de fonctions

Les formes do et let nomme sont reduites de facon similaire a la methode decrite dans le

standard Il en va de meme p our les formes delay La methode de reduction des formes delay

explique la presence de la fonction makepromise dont nous avons parle plus tot Le standard

ne donne pas de methode precise p our eectuer la transformation des formes quasiquote Nous

montrons quelques exemple representatifs des reductions que nous eectuons sur ces formes

a

hlist>vectori hconsi hconsi a

a

hlisti quasiquote hlisti unquote a

list a b

hconsi happ endi list a b

Il est imp ortant de noter que les parties qui ne contiennent pas susamment de unquotes

p our etre evaluables ne sont pas decomposees et sont incluses dans une forme quote

Ceci conclut la description des methodes que nous utilisons p our reduire les expressions du

programme source a quelques formes simples

CHAPITRE COMPILATION VERS DU CODEOCTETS

Transformation en arbres de syntaxe

La transformation du programme en arbres de syntaxe est une operation fort simple Il

sagit de transformer chaque expression de base en un no eud qui la symbolise Par exemple une

expression if est transformee de la facon suivante

if hexp i hexp i hexp i

if NN1 2N 3

Chaque expression interne a lexpression if est aussi tranformee en no eud Lexemple de cette

expression est le plus simple La plupart des autres expressions sont transformees en no euds qui

ont quelques champs supplementaires Ces champs supplementaires sont utilises plus tard comme

champs dattributs Le compilateur y met les resultats de calculs faits lors de traverseesde larbre

de syntaxe Par exemple les no euds symbolisant les references de variables contiennent entre

autre un champ indiquant si la variable en question est globale ou lexicale et un champ p our

indiquer la p osition de cette variable

Les no euds sont implantes a laide de vecteurs et le type du no eud est tout simplement un

p etit entier La discrimination entre les dierents types de no euds se fait donc tres rapidement

Elle seectue grace a un acces a un vecteur contenant les actions requises p our le traitement

des dierents no euds

Selection des fonctions de la librairie

Un programme Scheme typique nutilise pas toutes les fonctions de la librairie Or meme si

cette librairie est relativement reduite il est avantageux de ninclure que les fonctions requises

par le programme

Dans lap ercu de notre systeme nous mentionnons que certaines fonctions de la librairie sont

implantees directement dans le noyau et que les autres sont implantees en Scheme Les fonctions

implantees dans le noyau font toujours partie de linterprete resultant de la compilation Mais

celles qui sont implantees dans le chier de librairie p euvent etre incluses au b esoin seulement

La facon de pro ceder consiste a trouver toutes les references aux variables globales charger

la librairie identier les fonctions qui sont requises ceci inclut les fonctions dont dependent

celles qui sont directement utilisees par le programme

References globales

Cette phase consiste a trouver toutes les references aux variables globales Une reference a

une variable lexicale ne compte pas La liste des variables de lenvironnement lexical est donc

maintenue lors de cette recherche Si une variable nommant une fonction de la librairie nest

CHAPITRE COMPILATION VERS DU CODEOCTETS

jamais referencee alors on p eut en conclure que le programme nutilise pas cette fonction Du

moins il ne lutilise pas directement

Par la suite lorsque la librairie est chargee il est p ossible de faire lintersection entre la liste

des variables globales referencees et les noms des fonctions de la librairie On obtient ainsi la liste

des fonctions p otentiellement utilisees par le programme Il faut noter que cest un probleme

indecidable de verier si une fonction est veritablement utilisee Nous nous contentons donc de

cette approximation

La librairie

Le chier source de librairie Scheme contient plusieurs declarations et denitions de fonctions

Il est utilise a chaque compilation de programme

Tout dab ord nous montrons que les fonctions de la librairie et les expressions du programme

voient des espaces de noms dierents Ensuite nous decrivons lorganisation du chier de librai

rie Enn la methode dextraction est decrite

espaces de noms

Nous avons divise lespace de noms en deux Cette division sert a sassurer que les fonctions

de la librairie ont toujours acces aux autres fonctions quelles que soient les aectations faites

par le programme Nous illustrons ce fait avec un exemple Notre implantation de la fonction

standard utilise la fonction interne math Celleci additionne exactement deux nombres Elle

nest pas standard et par consequent la variable math nest pas visible depuis le programme

Nous disons que cette derniere est cachee Meme si le programme denit une variable globale

sapp elant math il ne sagit pas de la meme variable Un acces a cette variable est interprete

dieremment suivant quil est eectue dans le programme ou dans une fonction de la librairie

Les fonctions de la librairie voient toutes les variables denies ou declarees dans la librai

rie Les expressions du programme voient leurs propres variables et les variables visibles de la

librairie De plus meme si le programme mo die une des variables visibles de la librairie les

fonctions de la librairie continuent a voir le contenu original de cette variable

Organisation du chier de la librairie

Le chier de la librairie est separe en quatre parties Les parties sont delimitees par lexpres

sion f

La premiere partie sert a declarer les fonctions implantees dans le noyau ainsi que leur

numero Chaque fonction est declaree grace a une donnee de la forme car Cette partie

ne sert pas a dire si les fonctions en question sont visibles ou cachees

CHAPITRE COMPILATION VERS DU CODEOCTETS

quit

car

f

define max lambda x y if x y x y

f

quit

f

car

define caar lambda p car car p

define max lambda l foldl max l

f

On trouve les exemples suivants

La fonction quit du noyau est visible mais nonstandard

La fonction max est cachee et sert a limplantation de la fonction standard max

La fonction standard car du noyau sert entre autres a limplantation de la fonction

standard caar

Fig Extraits du chier de librairie

Les trois autres parties contiennent les declarations et denitions de toutes les fonctions

visibles et cachees La deuxieme partie regroup e les fonctions cachees La troisieme regroup e les

fonctions visibles nonstandard La quatrieme regroup e les fonctions standard donc visibles

Dans ces trois dernieres parties les declarations et denitions p euvent prendre une de trois

formes

Une denition ordinaire a la forme suivante

define hvariablei lambda hformalsi hb o dyi

La section dans laquelle se trouve une denition determine sa visibilite

Une denition dalias a la forme suivante

define hvariable i hvariable i

Cette forme p ermet de denir une variable qui doit contenir exactement la meme fonction

quune autre variable

Une declaration de fonction du noyau a la forme suivante

hvariablei

Elle sert a donner linformation de visibilite qui nest pas donnee dans la premiere partie

La distinction entre la troisieme et la quatrieme partie standard versus nonstandard est

seulement conceptuelle Le compilateur traite de la meme facon les fonctions qui en font partie

La gure illustre lorganisation du chier

CHAPITRE COMPILATION VERS DU CODEOCTETS

Factorisation du co de

An de reduire la quantite de co de necessaire a limplantation de la librairie les fonctions de

la librairie sont ecrites de facon a reutiliser le co de le plus p ossible Le travail qui est commun

a plusieurs fonctions est regroupe en fonctions generales Voici les principaux exemples

Les fonctions comme append et consistant a accepter un nombre variable darguments

et a appliquer un operateur binaire sur les arguments en asso ciant par la gauche ou par

la droite sont toutes implantees a laide de fonctions elevees de traitement de listes Ces

fonctions sont habituellement app elees fold

Les fonctions memq memv et member utilisent toutes la fonction cachee genericmember

qui est parametrable avec une fonction de comparaison

Assq assv et assoc utilisent la fonction genericassoc qui prend en parametre la fonc

tion de comparaison appropriee

Les comparaisons entre nombres sont implantees en utilisant la fonction genericcompare

p ouvant tester une relation entre les elements dune liste en les prenant deux a deux

Les comparaisons entre caracteres qui ne distinguent pas les ma juscules des minuscules

sont implantees comme une comparaison entre caracteres precedee dune reduction en

minuscules

Les comparaisons entre chanes de caracteres sont toutes implantees en utilisant un com

parateur de chanes generique qui retourne ou comme resultat Les fonctions de

comparaison de caracteres char et char ou charci et charci lui sont passees

et determinent du meme coup si la comparaison est sensible a la dierence entre ma juscules

et minuscules

Extraction des fonctions requises

Lorsque le compilateur lit le chier de librairie il classe les fonctions selon leur visibilite et

selon leur nature du noyau en Scheme ou simple alias Par une intersection entre la liste des

variables globales referencees par le programme et la liste des fonctions visibles de la librairie

il trouve celles qui sont directement requises par le programme Ensuite cellesci sont reduites

transformees en arbres et parcourues an da jouter les fonctions dont elles ont ellesmemes

b esoin Le tout se p oursuit jusqua ce que toutes les fonctions requises aient ete incluses

Le programme et les fonctions requises forment lensemble du co de Scheme a compiler Tou

tefois le compilateur ne melange pas ces deux parties car elles accedent a des espaces de noms dierents

CHAPITRE COMPILATION VERS DU CODEOCTETS

Traitement des constantes litterales

Les constantes litterales sont presentes dans un programme sous forme de nombres de chanes

de caracteres de caracteres de b o oleens et dexpressions quote Le compilateur accumule cer

taines des constantes lors de sa premiere traversee Les constantes sont traitees dieremment

selon quelles sevaluent a des donnees allouees ou nonallouees

Les constantes nonallouees comme le dans x ne subissent pas de traitement parti

culier Plus tard elles sont compilees en des instructions Les constantes allouees comme la liste

dans car sont traitees specialement Cest le traitement de ces constantes

qui est decrit dans cette section

Les constantes allouees contiennent necessairement au moins une paire un vecteur ou une

chane de caracteres Il ny a pas de representation externe p our les fermetures et les continua

tions Aussi les constantes allouees ont comme propriete detre des structures arb orescentes En

eet toute autre structure ne p eut secrire avec les representations externes p ermises en Scheme

Dans cette section nous utilisons le mot morceau p our designer un sousarbre de larbre

quest une constante

Les constantes allouees subissent les etapes suivantes elles sont decoupes en morceaux len

semble des morceaux est co de en une description la description est ecrite sous forme de tableau

do ctets en C le noyau rebatit les constantes lors de linitialisation Chacun de ces p oints est

maintenant traite plus en detail

Decoupage des constantes

Les morceaux

Durant la premiere traversee de larbre de syntaxe si le compilateur rencontre un no eud

representant une constante allouee il eectue le decoupage de la constante et inscrit un numero

de constante dans le no eud

Le decoupage dune constante consiste a numeroter chaque sousmorceau de cette constante

et a tous les decrire Par denition la constante ellememe est un de ses sousmorceaux La

description dun morceau consiste a decrire lob jet qui est sa racine La description inclut le

type une eventuelle valeur et les numeros des eventuels ls de la racine

Par exemple prenons la liste constante Il sagit dun paire contenant dans lordre le

nombre et la liste vide Il y a donc morceaux la paire ellememe le nombre et la liste vide

Chacun se voit attribuer un numero La description de la paire est le type pair et les numeros

des morceaux quelle contient La description du nombre est le type number et la valeur

La description de la liste vide est le type liste vide La constante recoit aussi un numero de

constante qui est generalement dierent de son numero de morceau

CHAPITRE COMPILATION VERS DU CODEOCTETS

Lalgorithme de decoupage accumule lensemble des constantes et morceaux quil traite Il les

conserve dans deux vecteurs Dans le premier vecteur se trouvent les descriptions des morceaux

Par une attribution en p ostxe des numeros de morceaux on fait en sorte que les numeros des

sousmorceaux dun morceau ont des numeros inferieurs au numero de ce dernier Le deuxieme

vecteur contient le numero de morceau de chaque constante Autrement dit il contient le numero

de lob jet a la racine de cette constante

Un exemple plus complet de decoupage est donne plus loin

La factorisation des constantes et des morceaux

Le numero donne a une constante nest pas necessairement unique Deux constantes iden

tiques au sens de equal se voient attribuer le meme numero Ceci implique que durant lin

terpretation du programme les deux expressions distinctes dans le source retournent la meme

constante au sens de eq Cette factorisation est p ermise par le R RS car il est interdit def

fectuer des mutations sur les donnees provenant de constantes litterales

La factorisation setend aussi aux morceaux Cestadire que tous les morceaux semblables

sont regroupes en un seul Ainsi apres reconstruction des constantes linterprete p ossede des

morceaux qui sont inclus dans plusieurs constantes dierentes

Exemple

Nous illustrons le decoupage a laide des deux constantes suivantes f s et a s

Les constantes recoivent resp ectivement les numeros et Les gures qui suivent montrent

leet du decoupage

Numero Morceau Description

f Boolean f

s String s

Empty list

s Pair

f s Pair

Number

a Char a

s Symbol

a s Vector

Numero de Numero de

constante morceau

CHAPITRE COMPILATION VERS DU CODEOCTETS

On p eut remarquer plusieurs choses dans ces gures Premierement la representation de

chaque morceau se refere si cest le cas seulement a des morceaux ayant un plus p etit numero

Deuxiemement il y a partage de la chane entre les deux constantes Troisiemement les morceaux

de tete des deux constantes nont pas les memes numeros que les constantes ellesmemes

Co dage des constantes

Une fois que toutes les constantes sont decoupees leur co dage p eut etre eectue La des

cription co dee consiste en une suite do ctets La description complete des constantes comp orte

les informations suivantes le nombre de morceaux la description de chaque morceau dans

lordre de leur numerotation le nombre de constantes le numero du morceau de tete de chaque

constante

Les nombres et les longueurs sont co des par deux o ctets Le premier o ctet est le plus signi

catif

A lexclusion du co dage de la description de chaque morceau le reste du co dage ne demande

pas vraiment dautres explications Il reste donc a montrer le co dage que nous employons p our

decrire les morceaux

Liste vide Elle est representee par le caractere

Paire La representation comprend le caractere suivi des numeros des deux champs de la

paire

Bo oleen Pour le b o oleen faux la representation est f Pour le b o oleen vrai elle est t

Caractere La representation est le caractere suivi dun o ctet decrivant le caractere

Chane de caracteres Le caractere est suivi de la longueur et de tous les caracteres de la

chane

Symbole Un symbole est represente par le caractere suivi du numero de la chane contenant

le nom

Nombre La representation est le caractere suivi du caractere ou selon le signe du

nombre et ensuite vient le nombre en valeur absolue Ce co dage p ermet de representer les

nombres independamment du taggage utilise par linterprete

Vecteur Il est represente par le caractere suivi de la longueur et du numero de chacun de

ses sousmorceaux

Cette representation nest pas la plus compacte que lon puisse imaginer Mais nous montrons

dans la pro chaine section que ca na pas b eaucoup de consequences

CHAPITRE COMPILATION VERS DU CODEOCTETS

Reconstruction des constantes

Cette etape du traitement des constantes ne fait pas partie du compilateur a strictement

parler mais nous preferons la decrire ici

Methode de reconstruction

Lors de linitialisation le noyau convertit la description co dee en un vecteur de constantes

Chaque constante est placee dans la case qui p orte son numero Les etapes de la reconstruction

sont les suivantes

Lire le nombre de morceaux et creer un vecteur de la longueur indiquee

Pour chaque entree du vecteur lire la description dun morceau batir celuici et le sto

cker dans le vecteur A ce p oint tous les morceaux sont reconstruits En particulier les

constantes aussi

Lire le nombre de constantes et creer un vecteur approprie

Remplir dans lordre chaque entree de ce vecteur avec le morceau dont le numero est

indiquee dans la description co dee Ce vecteur est le vecteur des constantes desire

Abandonner le vecteur des morceaux

La reconstruction est tres simple Tout est place dans le b on ordre par le compilateur Par la

suite levaluation dune expression devant retourner une constante allouee demande simplement

de faire une reference dans le vecteur des constantes

Abandon de la description co dee

Un des avantages de cette technique de transmission des constantes consiste en la p ossibilite

deliminer la description co dee une fois que le vecteur des constantes a ete construit

Avant linitialisation du noyau la description o ccup e un espace vaguement semblable a la

taille des constantes a rebatir Apres linitialisation seules restent les constantes Cette technique

est donc econome en memoire en plus detre simple

Malheureusement notre implantation en C ne comp orte pas cette p ossibilite dabandonner

la description co dee Toutefois une implantation en assembleur p ourrait eectuer cette tache

facilement En assembleur il est relativement aise de faire en sorte que le tableau contenant la

description se retrouve a la toute n de lexecutable Quand le programme est charge il no ccup e

pas toute la memoire du microcontroleur et lexcedent devient le tas En ayant la description

juste a cote de lexcedent de memoire le tas p eut setendre du debut de la description a la n

de la memoire

CHAPITRE COMPILATION VERS DU CODEOCTETS

(a) exec desc libre ACB D (b) exec "desc" tas ACB D (c) exec "desc" ctes tas ACB D

(d) exec ctes tas

a Lexecutable est charge au debut de la memoire du microcontroleur AC La

description des constantes se trouve a sa n BC b A linitialisation du tas la

description est transformee en une chane de caracteres Scheme Notons que le tas B

D commence au debut de lespace o ccupe precedemment par la description c Les

constantes sont reconstruites d La chane contenant la description est ab ondonnee

cestadire que la reference a la chane est ecrasee et le GC se charge eventuellement

de la ramasser

Fig Traitement ideal de la description des constantes

La gure montre les dierentes etapes de la reconstruction des constantes telle quelle

p ourrait etre faite en assembleur Elle montre de quelle facon on se debarrasse de la description

Autres techniques de transmission

Nous avons prefere notre appro che aux deux suivantes

La premiere consiste a pro duire une description du tas tel quil devrait avoir lair si les

constantes y avaient ete baties Cette appro che demande moins de travail de la part du noyau

Il na meme pas a interpreter quelque co de que ce soit p our obtenir les constantes Toutefois

elle augmente b eaucoup la complexite du travail a faire par le compilateur Celuici devient

completement dependant de la representation des ob jets dans linterprete et il devient plus dur

a mo dier

La deuxieme consiste a a jouter au debut du programme des expressions supplementaires

visant a construire les constantes et a les conserver dans un vecteur ou dans des variables a

nom unique Une expression constante consisterait en une reference a une de ces variables Cette

appro che nest pas trop complexe mais elle ne p ermet pas de se debarrasser de la description

des constantes cestadire des expressions a joutees Elle nest donc pas tres compacte

Malgre que notre appro che soit compacte elle demande tout de meme la jout dexpressions

au programme Il sagit du traducteur de la representation vers les constantes Ce traducteur

nest toutefois pas tres complexe etant donne la simplicite du co dage De plus cet espace est xe

CHAPITRE COMPILATION VERS DU CODEOCTETS

et ne depend pas de la quantite de constantes utilisees dans le programme source contrairement

a lappro che precedente

Lo calisation des variables

Cette partie comprend les deux taches suivantes Premierement trouver la p osition dans

lenvironnement global ou lexical dune variable impliquee dans une reference une aectation

ou une denition La p osition ainsi trouvee p ermet au generateur de co deo ctets de pro duire la

b onne instruction Deuxiemement recueillir la liste des variables globales

Un acces a une variable globale nest pas traite de la meme facon quun acces a une variable

lexicale

Lorsquil sagit dune variable lexicale il faut trouver les co ordonnees de la variable dans

lenvironnement devaluation en vigueur au moment de lacces a la variable La representation

employee dans les dernieres versions de linterprete est celle des blo cs dactivation chanes voir

la section Les co ordonnees dune variable lexicale sont donc le nombre de sauts de blo cs et

la p osition de la variable dans le blo c atteint En plus de trouver les co ordonnees dune variable

le fait que cette variable soit seule ou non dans son blo c est note Cette derniere information

sert ensuite lors de la generation du co deo ctets la p osition de la variable dans le blo c na pas

a etre speciee lorsque celleci est seule dans son blo c voir section

Lorsquil sagit dune variable globale il faut trouver son numero Toutes les variables glo

bales introduites par le programme ou la librairie recoivent un numero Une particularite de

lattribution des numeros vient du fait quil y a deux espaces de noms un p our la librairie

un p our le programme section Un acces a une variable du meme nom ne concerne pas

toujours la meme variable Cette numerotation p ermet en meme temps de compter les variables

globales

Valeur initiale des variables globales

Le compilateur trouve la valeur initiale des variables globales introduites par la librairie Ce

calcul est simple mais il p ermet deectuer plusieurs optimisations interessantes par la suite

Nous commencons par decrire le type de valeurs initiales que lon calcule p our ces variables

Nous voyons ensuite les optimisations que lon p eut eectuer a laide de ces valeurs Enn nous

decrivons tres rapidement la methode utilisee p our transmettre les valeurs initiales a linterprete

CHAPITRE COMPILATION VERS DU CODEOCTETS

Valeur initiale

Variables de la librairie

La fonction corresp ondant a chacune de ces variables est recherchee Ainsi on sait si la

fonction presente au depart dans une variable est une fonction du noyau ou une fermeture

Dans le premier cas le numero de la fonction est note Dans le deuxieme cas cest la lambda

expression generant la fermeture qui est notee Plus tard lors de la pro duction du co deo ctets

ladresse du corps de la fermeture p eut etre calculee

Il est imp ortant de noter que toutes les fonctions sous forme de fermetures qui sont introduites

par la librairie ont un environnement de denition vide Cest p ourquoi il est susant de noter

seulement la lambdaexpression La syntaxe des denitions admissibles dans le chier de librairie

voir section force les fermetures qui y sont introduites a avoir un environnement vide

La valeur initiale des alias cestadire des variables qui sont denies comme ayant la meme

valeur quune autre variable est calculee aussi Pour trouver leur valeur il sut de suivre les

alias jusqua ce que lon tombe sur une variable denie avec une valeur qui est une fonction du

noyau ou une fermeture

Variables du source

Nous ne cherchons pas a trouver les valeurs des variables introduites par le programme

Premierement les programmes ne sont pas organises aussi simplement que le chier de librairie

et le calcul de la valeur initiale p eut etre passablement complexe De plus a strictement parler

la valeur des variables au debut de lexecution du programme est arbitraire Deuxiemement la

valeur initiale des variables du programme p eut etre de nimp orte quel type En particulier les

fermetures p euvent p osseder un environnement de denition nonvide Ce type de valeur initiale

nest pas vraiment utile p our nos optimisations

Nous attribuons donc la valeur initiale f aux variables du programme

Utilite des valeurs initiales

Variables predenies

La premiere utilisation de la valeur initiale est tout simplement de connatre a lavance la

valeur qui doit etre mise dans certaines variables globales Il est preferable que les variables

globales du programme contiennent deja leur valeur initiale plutot que de generer du co de

o ctets representant des denitions completes En eet lors de la generation du co deo ctets p our

les fonctions de la librairie seul le corps des fonctions est compile dans le cas des fermetures et

rien nest genere dans le cas des fonctions du noyau Ainsi p our chaque fonction de la librairie

CHAPITRE COMPILATION VERS DU CODEOCTETS

les instructions p our la creation dune fermeture le cas echeant et p our le sto ckage de la valeur

sont eliminees

Connaissance a priori de la fonction app elee

Le fait de connatre la valeur initiale des variables de la librairie p ermet parfois de connatre

statiquement le resultat dune reference a une variable Le resultat p eut etre connu a deux

conditions la variable referencee est globale et a une valeur initiale connue cette variable ne

risque pas detre mutee

Nous voyons dans la section que ceci p eut p ermettre de remplacer lapp el dune certaine

fonction par lapp el dune fonction plus simple Le fait de connatre la fonction app elee p ermet

aussi de generer du co deo ctets plus compact principalement dans le cas dun app el de fonction

du noyau

Co dage des valeurs initiales

Une description de la valeur initiale de chaque variable est transmise au noyau via le chier

genere par la compilateur On se souvient que ce chier contient entre autres un tableau de

variables globales Or en C on p eut specier la valeur initiale des entrees dun tableau Dans

chaque entree du tableau une description de la valeur initiale Scheme est inscrite comme valeur

initiale C A linitialisation le noyau traduit les valeurs initiales C en des valeurs initiales Scheme

Ainsi lensemble des descriptions ne prend pas plus despace que les variables ellesmemes et

ces descriptions sont ecrasees par la traduction

La description de la valeur initiale dune variable globale est co dee de facon simple Si la

valeur initiale est le b o oleen f elle est co dee par Si la valeur initiale est la fonction du

noyau numero n elle est co dee par n Si la valeur initiale est une fermeture dont le corps

se trouve a ladresse n dans le co deo ctets elle est co dee par n

On sait que les mots machine du microcontroleur sont de bits seulement On p eut donc

se demander si ladresse dune fermeture p ourrait etre tellement elevee quelle causerait un

debordement Ce nest toutefois pas p ossible car le co deo ctets ne p eut depasser kiloo ctets

Le compilateur sassure que cette restriction est resp ectee La restriction est imp osee par la

representation des continuations voir a la section Le p oint de retour de la continuation

est sto cke dans le premier champ lequel est partage avec le bit de tag indiquant le soustype

propre aux continuations Ainsi il ny a que bits p our sto cker le p oint de retour dans les

continuations ce qui contraint la taille du co deo ctets a ne pas depasser Ko ctets

CHAPITRE COMPILATION VERS DU CODEOCTETS

Substitution des fonctions app elees

Nous parlons ici dune operation faite lors de la deuxieme traversee des arbres de syntaxe

du programme Cette operation vise a remplacer un app el a une fonction connue par un app el

a une fonction plus simple Cette operation p ermet principalement daugmenter lecacite de

linterpretation du programme Des economies despace p euvent aussi etre realisees car lapp el

dune fonction du noyau connue est plus concis que lapp el dune fermeture connue

En Scheme il y a plusieurs fonctions qui acceptent un nombre variable darguments Par

exemple la fonction additionne aucun nombre ou plus La fonction compare deux nombres

ou plus La fonction map applique une fonction a une liste ou plus La plupart de ces fonctions

sont souvent utilisees avec le meme nombre darguments Par exemple on additionne ou on

compare habituellement deux nombres On applique souvent une fonction a une seule liste

Tel que demande par le standard ces fonctions sont implantees avec tout le proto cole ne

cessaire a la gestion du nombre variable darguments Le b esoin de compacite exige dadopter

un traitement regulier plutot que decrire plusieurs specialisations de ces fonctions Reprenons

avec les memes exemples la fonction est implantee avec la fonction binaire math et la fonc

tion generale foldl la fonction est implantee avec loperateur math et la fonction generale

genericcompare la fonction map est implantee a laide de la fonction map qui applique une

fonction aux elements dune seule liste Pour voir limplantation complete de ces fonctions voir

la section A

Un exemple de substitution consisterait a remplacer un app el a la fonction par un app el a

la fonction math

Pour p ermettre une substitution de fonctions il y a plusieurs conditions a remplir Premiere

ment cest seulement dans les app els de fonctions que le compilateur eectue des substitutions

Deuxiemement on doit savoir statiquement quelle est la fonction qui est app elee Troisiemement

cette fonction doit p osseder une fonction substituante plus simple Quatriemement le nombre

darguments passes doit corresp ondre au nombre de parametres de la fonction substituante Si

toutes ces conditions sont remplies la substitution p eut avoir lieu

Voici la liste des substitutions que notre compilateur p eut faire

Remplacer la fonction append par append quand elle est appliquee sur deux arguments

Remplacer les fonctions et par les fonctions de comparaison analogues a

deux arguments

Remplacer les fonctions max min gcd et lcm par les fonctions binaires corres

p ondantes

Remplacer les fonctions makestring et makevector par des fonctions ne prenant que la

longueur en parametre

Remplacer la fonction apply par une fonction analogue a deux parametres

CHAPITRE COMPILATION VERS DU CODEOCTETS

define fib

lambda n

if n

n

fib n fib n

Fig Implantation de la fonction de Fibonacci utilisee pour un test de performance

Remplacer la fonction map par la fonction map qui applique une fonction sur les elements

dune seule liste

A lexception du cas de la fonction map les fonctions substituantes sont justement employees

de facon interne p our limplantation des fonctions substituees

Ces substitutions de fonctions p ermettent reellement dameliorer les p erformances Nous

avons pu le constater sur un programme calculant le eme nombre de Fib onacci voir la gure

Ce programme utilise constamment le genre de fonctions qui p euvent etre substituees Ses

p erformances en temps sont ameliorees par un facteur grace a la substitution

Pro duction du co deo ctets

Nous decrivons la methode que nous employons p our pro duire le co deo ctets Toutefois ce

nest pas ici que nous presentons le jeu dinstructions de la machine virtuelle pas plus que nous ne

montrons les instructions generees p our chaque forme syntaxique Ces p oints sont passablement

vastes et sont traites dans le pro chain chapitre

Nous presentons les items suivants lorganisation globale du co deo ctets lorganisation ar

b orescente du co de directement pro duit par la compilation des arbres de syntaxe la linearisation

de larb orescence la resolution des references aux etiquettes

Organisation globale du co deo ctets

Comme les variables introduites par la librairie sont initialisees implicitement il nest pas

necessaire de les initialiser explicitement avant lexecution du programme et cest le co de des

expressions de ce dernier qui o ccup e le debut du co deo ctets Les quelques expressions a joutees

au debut du programme par le compilateur so ccup ent de faire les initialisations necessaires

Parmi ces expressions gurent celles qui conservent les fonctions memv makepromise dans

des variables a nom unique

Lexecution debute donc a ladresse du co deo ctets Les expressions du premier niveau ont

leur co de disp ose dans lordre Une instruction darret du programme les suit Ensuite se trouve

le co de du corps de chacune des fermetures de la librairie

CHAPITRE COMPILATION VERS DU CODEOCTETS

Compilation des formes syntaxiques

Le co deo ctets nest pas genere immediatement sous sa forme nale Nous nous p ermettons

de le generer sous une forme arb orescente calquee sur la structure des arbres de syntaxe Nous

utilisons de plus un systeme detiquettage p our les references a des adresses qui ne sont pas

encore connues

Le co de brut pro duit par la compilation dun no eud consiste en une liste p ouvant contenir

des o ctets des denitions detiquettes des references a des etiquettes et dautres co des bruts

Les o ctets sont des nombres entre et inclusivement qui sont des instructions completes

ou des morceaux et qui sont conserves jusquau co deo ctets nal Les denitions detiquettes

sont comp osees du symbole def suivi dun numero detiquette Les references aux etiquettes

sont le symbole ref suivi dun numero detiquette

A titre dexemple le resultat de la compilation dun no eud if est une liste contenant pas

dans cet ordreci des souslistes representant le test le consequent et lalternative des o ctets

representant un saut conditionnel letiquette et la reference necessaires au saut conditionnel

etc

Linearisation et resolution des references

Cette derniere etape p ermet de transformer le co de qui est sous forme arb orescente et qui

est p ourvu detiquettes en un co de lineaire o u toutes les references sont resolues

La linearisation de larb orescence consiste simplement a ramener larb orescence en une seule

liste contenant o ctets symboles et numeros

La resolution des references se fait en deux passes La premiere determine la p osition de

chaque etiquette La seconde remplace les references aux etiquettes par ladresse des etiquettes

et elimine les denitions detiquettes Les adresses ainsi obtenues sont co dees en deux o ctets

A ce p oint le co deo ctets est represente par une liste do ctets Il ne reste qua lecrire sous

forme de tableau C

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

Chapitre

La machine virtuelle et le

co deo ctets

La seule partie de linterprete de co deo ctets quil reste a decrire est la machine virtuelle En

fait il y a deux machines virtuelles La premiere est celle qui est utilisee dans la premiere version

compilee La seconde est derivee de la premiere et p ermet de co der les programmes de facon

b eaucoup plus compacte Mais elle comp orte plus dinstructions et plusieurs dentre elles sont

des amalgames de plusieurs instructions Ce qui fait en sorte que la seconde machine virtuelle

est passablement plus complexe que la premiere

Nous commencons par decrire la premiere machine Nous montrons comment la compilation

seectue a laide du jeu dinstructions de cette machine Une description sommaire de la seconde

machine suit Nous nous interessons surtout aux transformations qui sont app ortees a la premiere

machine an dobtenir du co de compact Enn nous illustrons les gains despace obtenus avec

le passage de la premiere a la seconde machine Nous preferons illustrer la compilation a laide

de la premiere machine car elle est plus simple que la seconde

La premiere machine virtuelle

La premiere machine virtuelle vise la simplicite Elle disp ose de quelques registres Ses

quelques instructions p ermettent la compilation de toutes les formes syntaxiques de base

Les registres

Les registres de la machine sont les suivants Le registre pc contient ladresse dexecution

courante dans le co deo ctets Le registre val est laccumulateur de la machine Le registre env

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

contient lenvironnement devaluation courant Le registre args contient la liste darguments en

construction Le registre prev args contient une pile des listes darguments en construction

Le registre cont contient la continuation courante

La machine a acces a dautres registres qui sont utilises moins regulierement Ceuxci servent

a contenir quelques constantes couramment utilisees le vecteur des noms des symboles et le

vecteur des constantes allouees

Comp ortement general

Nous faisons un survol de la facon dont les expressions sont executees dans la machine

virtuelle La machine virtuelle nexecute pas vraiment les expressions directement elle suit

simplement les etapes decrites par les instructions generees par le compilateur

Levaluation dune expression est eectuee dieremment selon quelle se trouve en p osition

terminale ou nonterminale Dans tous les cas levaluation commence en ayant le registre pc qui

p ointe au debut du co de et le registre env qui contient lenvironnement courant Les dierences

se trouvent dans la facon de terminer levaluation de lexpression

Si lexpression est nonterminale elle retourne son resultat et preserve letat en vigueur avant

son evaluation Plus precisement levaluation de lexpression a les eets suivants sur les registres

Le registre val contient le resultat de levaluation Le registre pc p ointe sur linstruction qui suit

le co de de lexpression Les autres registres sont inchanges et ce p eu imp orte les mo dications

quils ont pu subir entre temps

Si lexpression est terminale elle retourne son resultat a la continuation courante Donc le

registre val contient le resultat de levaluation Tous les autres registres sauf prev args sont

args doit rester inchange Une expression extraits de la continuation courante Le registre prev

en p osition terminale p eut donc mo dier la plupart des registres comme elle le souhaite avant

de retourner son resultat

Une sauvegarde de letat est habituellement faite en creant une continuation La structure

de donnees que nous utilisons sert a sauver la valeur des registres pc env args et cont Cest

le fait de sauvegarder le registre cont dans les nouvelles continuations qui cree une chane de

structures

Dans certains cas une sauvegarde doit etre faite mais seulement du registre args Dans

les exemples de compilation nous voyons que lapp el dune fonction du noyau connue ne cause

pas dautre mo dication de letat que lecrasement du registre args La sauvegarde qui est

args eectuee dans de tels cas consiste a a jouter le contenu de args devant le contenu de prev

La jout se fait a laide dune paire Une sauvegarde avec une paire depense moins despace quune

sauvegarde avec une continuation Lorsque cest p ossible il est preferable de faire une sauvegarde

args dans prev

En quelque sorte ces deux formes de sauvegarde se partagent linformation contenue dans la

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

continuation conceptuelle Aussi lorsque le programme capture la continuation courante il ne

sut pas de faire une sauvegarde du premier genre et de retourner la structure resultante Il faut

plutot sauver la continuation resultante dans une paire avec le contenu du registre prev args

De cette facon la paire contient toute linformation quune continuation conceptuelle doit conte

nir Il est a noter que le registre val nest jamais sauve les continuations conceptuelles repre

sentent le reste du calcul elle ne connaissent pas le resultat du calcul courant

Nous mentionnons a la section quun interprete ne cree pas necessairement toutes les

continuations qui entrent en jeu dans une evaluation Cest le cas de notre interprete De facon

generale il ne cree une continuation que lorsquil doit sauver son etat

Operandes courts et longs

Dans le jeu dintructions de la machine virtuelle certaines instructions sont en deux versions

Une version prend un operande dun o ctet et lautre version prend un operande de deux o ctets

Par exemple linstruction qui sert a lire une variable globale est en deux versions Il est

clair quun programme p eut comp orter plus que variables globales Mais dans bien des cas

leur nombre est inferieur ou depasse de p eu Cest p ourquoi par generalite et par souci de

compacite il est utile davoir des versions longue et courte de cette instruction

Un tel choix rend limplantation de la machine virtuelle plus volumineuse mais nous en

decidons ainsi seulement lorsque la version courte est utilisee frequemment

Operande facultatif

Les instructions de lecture et decriture aux variables lexicales ont deux operandes mais le

second p eut et doit etre omis dans certaines situations Le premier operande indique le nombre

de blo cs de liaison a sauter p our parvenir au blo c adequat Le second indique la p osition de la

variable dans le blo c La description des environnements est donnee a la section

Or on sait que certains blo cs ne contiennent quune seule variable Ces blo cs sont representes

par des paires La machine en executant une de ces instructions commence par se rendre au

blo c approprie verie sil sagit dun blo c a plusieurs variables un vecteur et le cas echeant

lit le pro chain operande Sil sagit dun blo c a une variable loperande nest pas requis et le

compilateur ne la pas genere

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

Le jeu dinstructions

An de ne pas diluer les remarques imp ortantes dans trop de repetitions nous ne donnons

pas necessairement une description de chaque instruction separement

GetImmCte hdescriptioni Obtention dune constante non allouee Loperande est une des

cription de la constante en question La description indique le type et si necessaire la

valeur de la donnee Le resultat est mis dans VAL

GetAllocCte hnumberi Obtention dune constante allouee Loperande est le numero sur

bits de la constante La constante est tiree du vecteur des constantes Le resultat est mis

dans VAL

ReadVarXX hop erand i hop erand i Lecture dune variable lexicale ou globale Ces ins

tructions sont en versions courtes et longues Les operandes indiquent la p osition

de la variable Le resultat est mis dans VAL Le suxe XX de la mnemonique indique

seulement que cette mnemonique regroup e toutes les variantes de linstruction

WriteVarXX hop erand i hop erand i Ecriture dune variable lexicale ou globale Ce sont

les instructions decriture analogues a celles de lecture La valeur a ecrire est prise dans

val

MakeClos Creation dune fermeture Une fermeture est creee dapres les valeurs de pc et

env et est mise dans val Le p oint dentree indique dans la fermeture est pc Nous

expliquons ce calcul dans lexemple de la compilation des lambdaexpressions

CJump haddressi Saut conditionnel Si val contient la valeur f un saut est eectue a

ladresse indiquee par loperande

Jump haddressi Saut inconditionnel Un saut est eectue a ladresse indiquee par loperande

SaveCont haddressi Sauvegarde de letat de la machine dans une continuation Le p oint de

retour est indique par loperande La continuation est mise dans le registre cont

RestoreCont Retablissement de letat de la machine a partir de la continuation contenue

dans cont

InitArgs Initialisation de la liste darguments La liste vide est mise dans args

PushArg Empilement dun argument La valeur contenue dans val est a joutee a liste conte

nue dans args

Apply Application dune fonction La liste dans args contient une fonction en tete et des

arguments par la suite Cette fonction est appliquee sur les arguments Lexecution reprend

plus tard au p oint designe par la continuation courante et avec le resultat contenu dans

val

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

ApplyKernel hnumeroi Application dune fonction du noyau La fonction du noyau dont le

numero est indique par un operande dun o ctet est appliquee sur les arguments sto ckes

dans args Lexecution reprend immediatement avec le resultat dans val

FlushEnv Vider lenvironnement La liste vide est mise dans env

MakeBlockXX hsizei Creer un blo c de liaison avec ou sans parametre reste Ces instruc

tions sont en versions courtes et longues En Scheme un parametre reste est un parametre

qui recoit une liste contenant tous les arguments suivant les arguments requis Loperande

indique la taille du blo c dactivation a creer Les valeurs sont prises dans args et le nouveau

blo c est a joute devant lenvironnement contenu dans env

Stop Terminer lexecution du programme Linterprete cesse ses operations

SaveArgs Sauvegarde de la liste darguments en construction La liste darguments contenue

args dans args est a joutee au debut de la liste contenue dans prev

RestoreArgs Retablissement de la liste darguments precedente La premiere liste sauvee

dans la liste de prev args est retiree et placee dans args

Les exemples de compilation illustrent lutilite de chacune de ces instructions

Compilation des dierentes formes

Nous montrons la facon de compiler plusieurs des formes syntaxiques de base An de conden

ser lecriture du co de compile nous utilisons une notation mathematique symbolisant la compi

lation

C hexpi represente le co de genere p our lexpression hexpi si celleci se trouve en p osition

nonterminale



C hexpi represente le co de genere p our lexpression hexpi si celleci se trouve en p osition

terminale

C hexpi represente le co de genere p our lexpression hexpi Le p oint dinterrogation indique

indieremment une des deux p ositions Celles de ses sousexpressions qui sont compilees avec

un p oint dinterrogation sont compilees dans la meme p osition

Nous utilisons aussi une pseudomnemonique DefLabel qui ne corresp ond pas a une instruc

tion mais sert plutot a denir une etiquette

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

Constantes

C hConstanti

GetXXCte hop erandi



C hConstanti

GetXXCte hop erandi

RestoreCont

Pour simplier lexemple nous ne distinguons pas expressement entre les constantes allouees

et nonallouees

References de variables

C hvariablei

ReadVarXX hop erand i hop erand i



C hvariablei

ReadVarXX hop erand i hop erand i

RestoreCont

On utilise une des instructions de lecture de variable Dans le cas dune reference a une

variable globale loperande est son numero Dans le cas dune reference a une variable lexicale

les deux operandes designent le nombre de blo cs a sauter et la p osition dans le blo c atteint Le

dernier operande doit etre omis si le compilateur detecte quil sagit dun blo c a une variable

Aectations et denitions

Ces deux formes syntaxiques sont compilees presque de la meme facon La seule dierence

vient du fait quun no eud de denition ne p eut concerner quune variable globale Sans p erte de

generalite nous faisons lexemple sur une aectation

C set hvariablei hexpi

C hexpi

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

WriteVarXX hop erand i hop erand i



C set hvariablei hexpi

C hexpi

WriteVarXX hop erand i hop erand i

RestoreCont

Blo cs dexpressions

C begin hexp i hexp i hexp i

n n

C hexp i

C hexp i

n

C hexp i

n

La tres grande simplicite de la compilation des blo cs est une des raisons justiant leur

adoption comme forme de base dans notre compilateur

Conditions

C if hexp i hexp i hexp i

C hexp i

CJump hlab el i

C hexp i

Jump hlab el i

DefLabel hlab el i

C hexp i

DefLabel hlab el i

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS



C if hexp i hexp i hexp i

C hexp i

CJump hlab eli



C hexp i

DefLabel hlab eli



C hexp i

Quand lexpression est en p osition terminale ses deux dernieres sousexpressions le sont aussi

et le deroulement de lexecution ne depasse pas la n du co de de cellesci Cest p ourquoi il y a

un saut en moins que dans le cas o u lexpression est en p osition nonterminale

Lambdaexpressions

La compilation dune lambdaexpression pro duit du co de destine a deux usages distincts

Premierement il y a le co de lie a levaluation de la lambdaexpression cestadire a la creation

de la fermeture Deuxiemement il y a le co de lie au corps de la fermeture Voici ce qui est genere

C lambda hformalsi hb o dyi

MakeClos

Jump hlab eli

MakeBlockXX hsizei



C hb o dyi

DefLabel hlab eli

Il y a quelques details quil faut expliquer

Premierement linstruction MakeBlockXX nest pas generee sil ny a pas de parametres

formels

Deuxiemement grace a lexemple on p eut comprendre p ourquoi une instruction de creation

de fermeture xe le p oint dentree a pc Cest que durant lexecution de cette instruction pc

p ointe sur linstruction de saut qui o ccup e o ctets

Troisiemement lors de linvocation dune fermeture lenvironnement de denition est mis

dans env et ladresse du corps est mise dans pc De plus la liste des arguments est dans args

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

Ainsi linstruction de creation de blo c prend les arguments et en fait un blo c de liaison quelle

a joute devant lenvironnement de denition

Une lambdaexpression en p osition terminale genere un co de presquidentique a celui du cas

precedent Seule une instruction de retablissement detat est a joutee



C lambda hformalsi hb o dyi

C lambda hformalsi hb o dyi

RestoreCont

App els de fonctions

La compilation de ces formes est nettement la plus dicile Cest principalement parce que

nous traitons plusieurs sortes dapp els en fonction des informations statiques que le compilateur

arrive a calculer

Avant de montrer comment compiler chaque type dapp el nous montrons comment compiler

la liste des expressions fournissant les arguments de lapp el Cette liste p eut contenir ou non

lexpression qui retourne la fonction a invoquer Ensuite nous voyons les dierentes formes

dapp el La fonction a invoquer dans un app el de fonction p eut etre soit inconnue soit une

fonction du noyau soit une fermeture de la librairie ou encore une lambdaexpression De plus

lapp el est compile dieremment suivant quil est en p osition terminale ou non

Compilation de la liste darguments

La liste des expressions dans un app el est compilee dans lordre inverse Cestadire que la

derniere expression est la premiere a etre evaluee Cet ordre p ermet de separer plus facilement

les arguments qui sont requis de ceux qui vont dans un eventuel parametre reste

0

est une fonction La fonction C compile les listes darguments La fonction C

A A

auxilliaire

C hexp i hexp i

A n

InitArgs

0

hexp i hexp i C

n A

0

C

A

aucune instruction

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

0

C hexp i hexp i hexp i

A n n

C hexp i

n

PushArg

0

hexp i hexp i C

n A

On p eut remarquer que toutes les expressions dune liste darguments sont en p osition non

terminale et sont compilees comme tel

La fonction a invoquer est inconnue

C hexp i hexp i

n

SaveCont hlab eli

C hexp i hexp i

A n

Apply

DefLabel hlab eli



C hexp i hexp i

n

C hexp i hexp i

A n

Apply

Lorsque lapp el est en p osition terminale son evaluation ecrase le contenu de args et de

env Ca ne p ose pas de probleme puisque letat est retabli a la n de lapp el

La fonction a invoquer est une fonction du noyau

Dans un tel cas le proto cole dapp el est normalement moins lourd puisquil nest pas neces

saire de calculer lexpression en p osition app elante

C hkernelfunctioni hexp i hexp i

n

SaveArgs

C hexp i hexp i

A n

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

ApplyKernel hkernelfunctioni

RestoreArgs



C hkernelfunctioni hexp i hexp i

n

C hexp i hexp i

A n

ApplyKernel hkernelfunctioni

RestoreCont

Il y a toutefois une exception lorsque la fonction a invoquer est apply Cette fonction du

noyau a deux arguments sert a implanter apply Apply est la seule fonction du noyau qui risque

de mo dier letat de la machine virtuelle En eet elle lance linterprete sur un calcul inconnu

a priori

Lorsque la fonction est apply la compilation de lapp el se fait comme si la fonction a

invoquer etait inconnue

La fonction a invoquer est une fermeture de la librairie

Rapp ellons nous quune fermeture de la librairie a un environnement de denition vide

Ladresse du corps de la fermeture est connue

C hb o dyaddressi hexp i hexp i

n

SaveCont hlab eli

C hexp i hexp i

A n

FlushEnv

Jump hb o dyaddressi

DefLabel hlab eli



C hb o dyaddressi hexp i hexp i

n

C hexp i hexp i

A n

FlushEnv

Jump hb o dyaddressi

Meme si lapplication en tant que telle est plus longue en o ctets que lapplication generale

le fait de ne pas calculer lexpression en p osition app elante cause une economie despace

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

La fonction a invoquer est pro duite par une lambdaexpression

Une telle construction est rare dans un source Scheme ecrit par un programmeur Mais elle

est tres frequente parmi les expressions reduites Toutes les formes de liaison pro duisent ce type

de construction

Nous avons decide de traiter ce cas explicitement plutot que de laisser generer du co de qui

fait creer une fermeture qui lapplique et qui labandonne tout de suite apres De plus le co de

genere est plus compact

C lambda hformalsi hb o dyi hexp i hexp i

n

SaveCont hlab eli

C hexp i hexp i

A n

MakeBlockXX hsizei



C hb o dyi

DefLabel hlab eli



C lambda hformalsi hb o dyi hexp i hexp i

n

C hexp i hexp i

A n

MakeBlockXX hsizei



C hb o dyi

Linstruction MakeBlockXX est toujours necessaire contrairement au cas de la compilation

des lambdaexpressions Une lambdaexpression en p osition app elante p ossede toujours des pa

rametres Sinon luniformisation des formes de base section laurait eliminee plus tot

Qualite de la compilation

La methode de compilation que nous venons de decrire nest pas parfaite Si on est attentif

on p eut se rendre compte que plusieurs formes p ourraient etre mieux compilees

Pour ne citer quun exemple la compilation des lambdaexpressions nest pas tres b onne Le

co de du corps est genere sur place et il faut faire un saut pardessus une fois que lon a cree la

fermeture Si la lambdaexpression est en p osition terminale le co de genere comp orte un autre

defaut Le saut est fait pardessus le corps an de systematiquement tomber sur une instruction

RestoreCont

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

On p eut trouver plusieurs autres defauts Il faudrait de nouvelles instructions p our pallier

a la plupart des defauts Cest p ourquoi la machine virtuelle est mo diee a partir de la version

suivante de linterprete

La deuxieme machine virtuelle

Cette machine est plus complexe et resulte de nombreux a jouts et mo dications eectues

sur la premiere machine Nous ne presentons pas son jeu dinstructions car il est long et tres

ennuyeux Nous ne tenons pas non plus a donner dexemples de compilation p our les dierentes

formes syntaxiques Nous voulons plutot discuter de certains des changements app ortes a la

premiere machine qui ont p ermis dab outir a la deuxieme

Instructions specialisees

Plusieurs instructions specialisees sont a joutees Elles consistent en une version courte de

certaines instructions utilisees frequemment

Il y a des instructions servant a retourner la liste vide chaque b o oleen un caractere ou un

nombre representable sur un o ctet Une constante construite dont le numero est inferieur a

chose tres frequente p eut etre obtenue grace a une instruction courte

Les lectures de variables lexicales sont frequentes surtout en certaines co ordonnees Nous

avons cree instructions specialisees p our les co ordonnees les plus utilisees En notation sauts

de blocs position les cas les plus frequents sont dans lordre

et Resp ectivement ces cas representent et

des lectures de variables lexicales Donc au total environ de ces lectures Le co de utilise

p our amasser ces statistiques est un ensemble de fonctions de la librairie

Les instructions de fabrication de blo cs dactivation et de creation de fermeture ont aussi des

versions specialisees p our quelques cas

Fusion dinstructions

La compilation vers le co de de la premiere machine place souvent certaines instructions avant

ou apres certaines autres Plusieurs instructions ont ete creees p our remplacer deux anciennes

instructions ou plus

Lexemple suivant montre des instructions qui se suivent Toutes les fois o u letat de la

machine est sauvee dans une continuation instruction SaveCont cest parce quil y a un app el

qui doit etre fait Or la premiere etape dun app el consiste toujours a initialiser le registre args

instruction InitArgs Nous avons donc remplace linstruction SaveCont par une instruction

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

amalgamee SaveContInitArgs

Diverses nouvelles instructions

Quelques exemples de fonctions diverses sont presentes

Une nouvelle instruction p ermet deliminer le premier blo c de liaison dans lenvironnement

Ainsi il nest plus necessaire de creer une continuation p our restaurer lenvironnement apres

lexecution dune forme de liaison en p osition nonterminale Une forme de liaison reduite et en

p osition nonterminale n de la section ne necessite plus une sauvegarde de letat dans

une continuation Lenvironnement initial p eut etre retrouve grace a la nouvelle instruction

Lorsque letat est sauve avant de faire un app el le p oint de retour qui est specie est tou

jours ladresse qui suit linstruction Apply Le proto cole est legerement change Linstruction

SaveCont ne specie plus de p oint de retour Cest linstruction Apply qui xe le p oint de retour

avant deectuer lapplication comme telle Il ny a donc plus de p oint de retour a indiquer

explicitement p our ce type dapp els

Une serie dinstructions dun o ctet ont ete a joutees Une par fonction du noyau Linvocation

directe dune fonction du noyau prend maintenant un o ctet de moins Cette serie dinstructions

ne complique pratiquement pas limplantation de la machine virtuelle En eet il sut de donner

des numeros consecutifs aux instructions de la serie et limplantation na pas a traiter chacune en

particulier Nous avons donne le numero n a linstruction qui invoque la fonction numero

n du noyau

Empilement automatique

Linstruction qui est la plus frequente est PushArg qui cause lempilement dans args de la

valeur contenue dans val Maintenant lempilement est automatique a la suite de levaluation

des expressions En fait lempilement est integre aux instructions qui terminent normalement

le co de dune expression

Lorsquun empilement nest pas voulu ce qui est le cas le plus rare un depilement explicite

est genere Un empilement nest pas desire par exemple apres lexecution des n premieres

expressions dune expression begin qui en contient n En eet seul le resultat de la derniere

expression doit etre conserve

Imp ortance de la denition des instructions

Le passage de la premiere machine virtuelle a la seconde p ermet de reduire la taille du

co deo ctets de facon appreciable Nous utilisons deux programmes Scheme an de faire les tests

CHAPITRE LA MACHINE VIRTUELLE ET LE CODEOCTETS

Le premier programme est minuscule Il ne comp orte quune expression Celleci cree une liste

de toutes les fonctions visibles de la librairie Ceci cause linclusion de toutes ces fonctions En

eet le compilateur ne fait pas danalyses assez p oussees p our determiner que seule la fonction

list est eectivement utilisee Il est imp ortant de mentionner que le chier source de la librairie

est un chier de kiloo ctets

Le second programme est un mo dule dun programme reel un generateur danalyseur lexical

Le mo dule ne cause pas linclusion de toutes les fonctions de la librairie mais cest un chier

denviron o ctets environ lignes avec p eu de commentaires

Les deux programmes pro duisent chacun pres de o ctets quand ils sont compiles avec

le jeu dinstructions de la premiere machine Tandis quavec le jeu dinstruction de la seconde

machine ils pro duisent pres de et o ctets resp ectivement Il sagit donc dune nette

amelioration

On p eut faire deux observations a partir de ces chires Premierement la librairie au grand

complet no ccup e pas plus de o ctets ce qui est tres p eu despace Deuxiemement il est

p ossible de compiler des programmes relativement imp osants et de les faire entrer sur le micro

controleur Toutefois les programmes doivent etre assez economes en consommation de memoire

dans tous les cas le tas ne p eut contenir quun p etit nombre dob jets Par exemple un minuscule

programme qui ne fait que construire une longue liste p eut allouer environ paires au

maximum en supp osant quil ny a pas la limite des paires imp osee par le taggage voir

gure

CHAPITRE LETAT ACTUEL DES TRAVAUX

Chapitre

Letat actuel des travaux

Nous commencons par decrire concretement letat de linterprete et du compilateur Ensuite

nous mentionnons plusieurs ameliorations qui p ourraient etre app ortees a lensemble du systeme

Details dimplantation

Le compilateur

Le compilateur est implante en Scheme Il nest pas concu p our etre ultrarapide bien que

malgre tout il se trouve a etre relativement ecace Certaines parties devraient etre reprogram

mees dieremment si lecacite devenait cruciale

An de donner une idee de sa rapidite nous decrivons lenvironnement sur lequel nous lavons

teste et quel genre de programme il a compile Nous avons employe linterprete Scheme scm

IntScm ecrit par Aubrey Jaer p our faire fonctionner notre compilateur La machine employee

est un DEC AXP dote dun micropro cesseur DEC Alpha tournant a MHz sous OSF

version et p ossedant Mo ctets de memoire vive Le programme test a compiler est le

chier de test dimplantation ecrit par Aubrey Jaer TestImp Il sagit dun source denviron

kiloo ctets Environ une centaine parmi le millier de lignes ont ete mises en commentaire

parce que nous ne voulons pas tester les longs nombres les nombres en p oint ottant et les

entreessorties Ce programme en testant presque toutes les fonctions force linclusion de la

quasitotalite de la librairie La compilation de ce programme prend environ secondes Notre

compilateur a donc une ecacite bien tolerable en pratique

CHAPITRE LETAT ACTUEL DES TRAVAUX

Linterprete

De ce cote le travail nest pas aussi complet Nous navons pas veritablement introduit

linterprete sur le microcontroleur Toutefois nous nous sommes assures que cette tache est

p ossible

Le noyau est implante en C et nous avons faits des tests sur la taille de linterprete a laide

dun compilateur C qui compile vers des instructions de notre microcontroleur Il sagit du com

pilateur gcc de GNU muni dun generateur de co de p our le microcontroleur Cette adaptation

vient de Otto Lind CompGcc

Ce compilateur ne genere pas du co de binaire aussi compact quun programmeur humain

p ourrait le faire Un des gros problemes de ce compilateur vient du fait que le mo dule de

generation du co de ment au compilateur en declarant quil y a plusieurs registres Or ces

registres sont simules par le generateur de co de Toute instruction de manipulation de registres

que le compilateur veut pro duire est traduite en deux ou trois instructions reelles De plus la

gestion de la pile C requiert plusieurs instructions par fonction Or notre interprete nutilise

pas la recursivite Une implantation de linterprete directement en assembleur serait b eaucoup

plus compacte

Malgre tout la compilation de linterprete p our le microcontroleur pro duit un co de binaire

denviron Ko ctets librairie incluse Ce qui nous p ermet de conclure que linterprete p ourrait

etre introduit dans le microcontroleur Le programme que nous utilisons p our ce test est le

premier programme decrit a la section

Un des manques de linterprete concerne les constantes litterales La technique de transmis

sion des constantes allouees prevoit de se debarrasser de la description des constantes une fois

que cellesci sont reconstruites section Notre implantation ne p eut malheureusement pas

se debarrasser de la description

Mesures de taille et de p erformance

Comparaison de la taille des executables

Dans lintroduction nous mentionnons que nous navons pas trouve dinterprete Scheme

susamment p etit p our etre utilise directement sur un microcontroleur Cest en compilant

plusieurs interpretes Scheme sur une station de travail DEC decrite a la section que

nous avons pu le verier Tous ces interpretes proviennent du Scheme Repository un site

o u la plupart des programmes et informations les plus interessants a prop os de Scheme sont

accumulees

La gure presente la taille de lexecutable derivant de plusieurs implantations Les im

: ftpftpcsindianae dup ub sche me repo sit ory

CHAPITRE LETAT ACTUEL DES TRAVAUX

Implantation Taille de lexec

fools Ko ctets

minischeme Ko ctets

scm e Ko ctets

siod Ko ctets

scheme Ko ctets

Fig Taille de lexecutable de plusieurs interpretes

plantations ne sont pas toutes mentionnees Ca p eut etre le cas si elles sont absentes du Scheme

Repository ou trop volumineuses p our etre p ossiblement adaptables a un espace tres reduit

Notre interprete est mentionne sous le nom scheme p our microcontroleur dans la gure Il

est compile avec la librairie complete Evidemment il faut sattendre a ce que la taille de lexe

cutable p our DEC soit dierente de celle de lexecutable p our le microcontroleur Sur DEC les

instructions sont plus volumineuses et la librairie C standard o ccup e un espace considerable

Clairement la seule implantation qui ait une taille qui se rappro che de celle de notre inter

prete est minischeme Toutefois celleci est passablement incomplete Il manque de nombreuses

fonctions a la librairie Tout particulierement en ce qui concerne le traitement des chanes de

caracteres Certaines fonctions sont implantees mais ne p ermettent pas de traiter un nombre

variable darguments comme lexige le standard

Nous tenons a preciser que ces tests montrent seulement que les autres interpretes tels que

distribues ne p euvent etre utilises dans le cadre dun microcontroleur Nous nexcluons pas

que certains dentre eux puissent etre mo dies en des versions noninteractives susamment

p etites Cest dailleurs le cas avec notre interprete seules les versions compilees sont adequates

les versions interactives sont trop volumineuses

Tests de p erformance

Meme si nous navons pas introduit linterprete dans le microcontroleur il imp orte den

verier les p erformances Nous avons donc eectue des tests sur une station de travail DEC voir

section Les tests consistent a comparer sur quelques programmes les temps dexecution

de notre interprete avec ceux de deux interpretes connus

Les deux interpretes de reference sont linterprete scm et linterprete Gambit gsi de Marc

Feeley IntGsi La gure montre les temps dexecution de notre interprete nomme scheme

dans la gure par rapp ort a ceux des interpretes de reference

On p eut constater que notre interprete est passablement lent Le cas du programme browse

est nettement plus pathetique que les autres La raison de cette dierence marquee est luti

lisation frequente de la fonction stringsymbol Contrairement aux implantations qui vise

lecacite notre interprete ne sto cke pas lensemble des symboles dans une table de hashage

La recherche dun nom de symbole implique une recherche dans toute la liste des noms La

CHAPITRE LETAT ACTUEL DES TRAVAUX

T T T T T T T

scheme scm scheme scm gsi scheme gsi

browse s s s

cpstak s s s

destruc s s s

fib s s s

nqueens s s s

primes s s s

Fig Tests de performance comparatifs

creation dun nouveau symbole demande donc un temps prop ortionnel au nombre de symbole

preexistants Donc n app els a la fonction stringsymbol demandent un temps dans O n

le pire cas etant atteint quand de nouveaux symboles sont crees a chaque app el

Les principales causes de la lenteur de notre interprete sont le GC temps reel limplantation

des fonctions de la librairie en reutilisant le co de au maximum et une tendance generale a

favoriser la compacite a la p erformance dans le noyau et le co deo ctets

Ameliorations p ossibles

Le de de realiser une implantation la plus compacte p ossible p eut etre aussi dur a relever

que le de de rendre une implantation la plus ecace p ossible Comme il ny a pas b eaucoup

de travaux eectues du cote de la compacite il faut explorer toutes les directions a la fois Nous

navons donc pas pu approfondir chaque asp ect etant donne quils sont nombreux

La liste de choses qui p ourrait etre ameliorees p ourrait devenir tres longue si lon voulait

tout mentionner Nous nous concentrons sur les p oints principaux

Les nombres en p oint ottant et les grands entiers p ourraient etre implantes Comme ces

a jouts p euvent augmenter sensiblement la taille de linterprete lutilisateur du systeme

devrait p ouvoir controler linclusion de ces services

Lorsque les noms des symboles presents dans un programme ne sont pas requis linterprete

ne devrait pas les conserver Les symboles dont nous parlons ici ce sont les symboles

sous formes de donnees et non pas ceux servant didenticateurs Le compilateur p ourrait

detecter si les fonctions qui creent des symboles ou qui retournent leur epellation sont

utilisees Lorsquelles ne le sont pas il devient inutile de conserver lepellation du nom de

chaque symbole Un numero tagge serait susant p our les distinguer les uns des autres

On a vu que les blo cs chanes sont plus compacts lorsque des variables sont partagees par

plusieurs fermetures La representation plate est plus compacte lorsque p eu de variables

doivent etre conservees parmi toutes celles de lenvironnement courant Il existe probable

ment une facon de combiner le partage des blo cs de variables communs et la selection des

CHAPITRE LETAT ACTUEL DES TRAVAUX

variables

Le compilateur p ourrait employer certaines analyses deja existantes qui servent a eviter

dallouer des fermetures lorsque ce nest pas necessaireCes analyses sont concues a lorigine

p our lecacite mais elles p euvent eventuellement servir a limiter la consommation de

memoire Par exemple des techniques p ossiblement utiles sont le lambdalifting PJ

et lanalyse cfa Shi

La substitution des fonctions par des fonctions plus simples p eut causer lexistence de co de

mort Par exemple si a tous les endroits o u la fonction est utilisee elle est remplacee par

la fonction math alors le co deo ctets decrivant la fonction ne p eut plus etre atteint

Une passe dans le co deo ctets p ourrait p ermettre deliminer le co de inutile

La fonction de reconstruction des constantes allouees est ecrite en Scheme et cause linclu

sion de quelques autres fonctions Scheme Or selon la nature des constantes ces autres

fonctions ne sont pas toutes utilisees Il serait interessant dadapter la fonction de recons

truction p our chaque programme an de limiter linclusion des fonctions a celles qui sont

eectivement utilisees

Le noyau utilise p ourrait etre adapte aux b esoins dun programme grace a des options

speciees par le programmeur lors de la compilation Entre autre le choix dutiliser un

GC temps reel ou non devrait etre laisse au programmeur Un GC blo quant est bien plus

ecace Aussi le traitement des continuations comme ob jets de premiere classe a une

inuence certaine sur linterprete Si le programmeur certie que son programme nutilise

jamais les continuations p our eectuer autre choses que des fonctions de sortie nonlo cale a

usage unique alors le noyau p eut etre implante plus ecacement On p ourrait p ermettre de

choisir une representation des donnees parmi plusieurs La liste des choses parametrables

p ourrait sallonger encore

CHAPITRE CONCLUSION

Chapitre

Conclusion

Notre travail visait a etudier les dierents asp ects relies a un systeme Scheme compact Le

but principal consistait a montrer quon p eut faire une implantation susamment compacte

p our p ouvoir fonctionner sur un microcontroleur Les buts secondaires etaient de trouver ou

developper un GC temps reel implantable de facon compacte et de choisir des techniques p or

tables

Les dierents asp ects que nous avons etudies sont la representation des donnees principale

ment en ce qui concerne le typage les symboles les continuations et les environnements lexicaux

le domaine des GC temps reel le developpement dun mo dele dexecution tres compact utilisant

la compilation

Nous avons obtenu des resultats p ositifs a deux p oints de vue Premierement lors de la

recherche dun GC temps reel adequat nous avons developpe une nouvelle technique Il sagit

dun GC temps reel compactant a un espace Cette technique a ete publiee dans une conference

au debut de lannee DFS

Deuxiemement malgre que notre implantation du systeme nait pas tourne sur un micro

controleur comme tel nous avons pu montrer quune implantation dun systeme de program

mation Scheme p our microcontroleur est tout a fait p ossible En eet lexecutable pro duit par

la compilation de linterprete complet a une taille de seulement Ko ctets

Nous estimons que nos ob jectifs sont atteints

CHAPITRE CONCLUSION

Remerciements

Je tiens surtout a remercier mon directeur de recherches Marc Feeley p our toute laide

app ortee tant durant le travail de recherche que durant la redaction de ce memoire Linteret

quil p ortait a mon travail etait toujours une source de motivation Et enn il faut ladmettre

sa patience est une qualite qui a ete sollicitee souvent dans nos relations

Je tiens aussi a remercier mes camarades detudes p our leur supp ort moral et p our leur aide

en general Leurs encouragements et leurs suggestions ont ete fort appreciees

Enn je tiens a remercier les membres de ma famille p our leur supp ort moral Ils mont

toujours soutenu surtout dans les moments les plus durs

Remerciements au CRSNG qui a supp orte nancierement mes etudes de matrise

BIBLIOGRAPHIE

Bibliographie

Bak Henry G Baker Jr List pro cessing in real time on a serial computer Communica

tions of the ACM avril

Bak Henry G Baker Jr The Treadmill Realtime garbage collection without motion

sickness ACM SIGPLAN Notices mars

Bar Jo el Bartlett Compacting garbage collection with ambiguous ro ots Technical Re

p ort Digital Equipment Corp oration Western Research Lab oratory Palo Alto

California Fevrier

Bro Ro dney A Bro oks Trading data space for reduced time and co de space in realtime

collection on sto ck hardware Proceedings of the ACM Symposium and

Functional Programming ao ut Austin Texas

BW HansJuergen Bo ehm et Mark Weiser Garbage collection in an unco op erative en

vironment Software Practice and Experience Septembre

Che C J Cheney A nonrecursive list compacting algorithm Communications of the

ACM novembre

CN Jacques Cohen et Alexandru Nicolau Comparison of compacting algorithms for

garbage collection ACM Transactions on Programming Languages and Systems

o ctobre

CompGcc Auteur Otto Lind Source

ftpwattsoneeualbe rta ca pub mot orol a hc g ccg cc fs fta rg z

Del Delacour Vincent Un gestionnaire memoire independant p our K Rapport de re

cherche de lICSLA LIX Ecole p olytechnique Lab oratoire dinformatique

o ctobre

DFS Danny Dube Marc Feeley et Manuel Serrano Un GC temps reel semicompactant

Actes des Journees Francophones des Langages Applicatifs ValMorin Que

b ec Canada janvier

DLM Edsger W Dijkstra Leslie Lamp ort A J Martin C S Scholten et E F M

Steens Onthey garbage collection An exercise in co op eration Communications

of the ACM Novembre

BIBLIOGRAPHIE

FL Marc Feeley Guy Lapalme Using Closures for Co de Generation Journal of Com

puter Languages Vol No pp Pergamon Press

FL Marc Feeley Guy Lapalme Closure Generation Based on Viewing Lambda as Ep

silon plus Compile Journal of Computer Languages Vol No pp

Pergamon Press

Gud David Gudeman Representing Type Information in Dynamically Typed Language

Department of Computer Science The University of Arizona TR Octob er

IntGsi Auteur Marc Feeley Source

ftpftpiroumontrea lca pu bpa ral lele ga mbit ga mbc tgz

IntMini Auteur Atsushi Moriwaki Source

ftpftpcsindianae dup ub sche me repo sit ory imp min isc heme ta rgz

IntScm Auteur Aubrey Jaer Source

ftpftpcsindianae dup ub sche me repo sit ory imp scm e tar gz

IntSiod Auteur George Carrette Source

ftpftpcsindianae dup ub sche me repo sit ory imp sio d t ar gz

Mor Morris F L A time and spaceecient garbage compaction algorithm Comm

ACM

Nil Nilsen Kelvin Garbage collection of strings and linked data structures in real time

Software Practice and Experience juillet

NS K D Nilsen et W J Schmidt A HighPerformance HardwareAssisted RealTime

Garbage Collection System En soumission

PJ Peyton Jones S L The Implementation of Languages

Englewoo d Clis NJ PrenticeHall

R RS Revised Report on the Algorithmic Language Scheme William Clinger et Jonathan

Rees editeurs

Shi O Shivers The Semantics of Scheme ControlFlow Analysis Proceedings of PEPM

ACM Sigplan Notices septembre

Ste Guy L Steele Jr Multipro cessing compactifying garbage collection Communica

tions of the ACM septembre

TestImp Auteur Aubrey Jaer Source

ftpftpcsindianae dup ub sche me repo sit ory cod ela ng test sc m

Wil Paul R Wilson Unipro cessor garbage collection techniques Dans Yves Bekkers

et Jacques Cohen editeurs International Workshop on Memory Management nu

mero dans Lecture Notes in Computer Science pages St Malo France

Septembre SpringerVerlag

BIBLIOGRAPHIE

Yua Taichi Yuasa Realtime garbage collection on generalpurp ose machines Journal of

Systems and Software

ANNEXE A SOURCES DU SYSTEME

Annexe A

Sources du systeme

Les dierents chiers comp osant le systeme de programmation Scheme p our microcontroleur

sont recopies ici Il sagit du systeme nal Il comp orte le compilateur vers du co deo ctets et

le noyau est dote du GC temps reel et de linterprete p our le second jeu dinstructions de la

machine virtuelle Tout dab ord les chiers sources du noyau sont presentes Ensuite vient le

chier contenant la librairie suivi du compilateur vers du co deo ctets Enn a titre dillustration

le resultat de la compilation dun p etit programme est presente

A Sources du noyau

Le noyau est constitue de deux chiers noyauh et noyauc Tel quillustre a la gure

un executable est forme en compilant le noyau avec un chier pro duit par le compilateur de

co deo ctets

A noyauh

1: include stdioh

2: include stdlibh

3: include stringh

4:

5: Personnalisation

6: define TRUE

7: define FALSE

8:

9: Configuration

10: define CHARSPERINT sizeof int

11: define LOGCPI

12: define DEFAULTHEAPSIZE

13:

14: Variables globales C

15: extern int mem

16: extern int memlen nbhandles nbobj handle

17: extern int memnext memfree memstack

18: extern int gcmark gccompact gcratio gctime

19: extern int gctrav gcvecting gccut

20: extern int gcold gcnew gclen gcsrc gcdst gcstate

21: extern int nbsymbols

22: extern int evalpc

23: extern int cprimvoid

24: extern int cprimint

25: extern int cprimint int

26: extern int cprimint int int

27:

28: Variables globales SCM

29: define NBTEMPS

30: define conscar globs

31: define conscdr globs

32: define stringcopys globs

33: define makeclosenv globs

ANNEXE A SOURCES DU SYSTEME

34: define listcopytete globs

35: define listcopycourant globs

36: define listcopyl globs

37: define makerestframeframe globs

38:

39: define NBSINGLES

40: define scmempty globsNBTEMPS

41: define scmfalse globsNBTEMPS

42: define scmtrue globsNBTEMPS

43: define scmsymbolnames globsNBTEMPS

44: define scmconstants globsNBTEMPS

45:

46: define evalval globsNBTEMPS

47: define evalenv globsNBTEMPS

48: define evalargs globsNBTEMPS

49: define evalprevargs globsNBTEMPS

50: define evalcont globsNBTEMPS

51:

52: define NBGLOBS NBTEMPS NBSINGLES

53: extern int globs

54:

55: Description des types et macros du GC

56: define BITH x

57: define BITH x

58: define BITB x

59: define BITB x

60: define BITB x

61: define BITB x

62:

63: define NUMMASK BITB

64: define NUMVAL BITB

65: define TYPEMASK BITH BITH BITB

66: define TYPEPAIR

67: define TYPECLOS BITH

68: define TYPEOTHER BITH

69: define TYPESPEC BITH BITH

70: define CONTMASK BITB

71: define CONTVAL BITB

72: define VECTINGMASK BITB BITB

73: define VECTORVAL

74: define STRINGVAL BITB

75: define SYMBMASK BITH BITH BITB BITB

76: define SYMBVAL BITH BITH BITB

77: define SPECMASK BITH BITH BITB BITB BITB BITB

78: define SPECCHAR BITH BITH

79: define SPECCPRIM BITH BITH BITB

80: define SPECBOOL BITH BITH BITB

81: define NULLVAL xfffffffc

82: define FALSEVAL xffffffe

83: define TRUEVAL xfffffff

84: define HANDLEMASK TYPEMASK

85:

86: define CPREDNUMBERd d NUMMASK NUMVAL

87: define CPREDPAIRd d TYPEMASK TYPEPAIR

88: define CPREDCLOSUREd d TYPEMASK TYPECLOS

89: define CPREDOTHERd d TYPEMASK TYPEOTHER

90: define CPREDSPECIALd d TYPEMASK TYPESPEC

91: define CPREDSYMBOLd d SYMBMASK SYMBVAL

92: define CPREDCHARd d SPECMASK SPECCHAR

93: define CPREDCPRIMd d SPECMASK SPECCPRIM

94: define CPREDBOOLEANd d SPECMASK SPECBOOL

95:

96: define GCMARK

97: define ISMARKEDdata memmemSCMTOHANDLEdata GCMARK

98:

99: Fonctions de manipulation des donnees

100:

101: define SCMTOHANDLEd d HANDLEMASK

102: define HANDLETOPAIRi i TYPEPAIR

103: define HANDLETOCLOSUREi i TYPECLOS

104: define HANDLETOOTHERi i TYPEOTHER

105: define TOSCMCHARc c SPECCHAR

106: define TOCCHARc c xff

107: define CSTRINGLENs memmemSCMTOHANDLEs

108: define SYMBOLNUMBERs s SYMBMASK

109: define NUMBERTOSYMBOLn n SYMBVAL

110: define TOSCMNUMBERn n NUMVAL

111: define CVECTORLENv memmemSCMTOHANDLEv

112: define CMAKECPRIMn n SPECCPRIM

113: define CPRIMNUMBERc c SPECMASK

114: define PCTOPCTAGp p CONTVAL

115: define PCTAGTOPCp p

116: define CHAMPdchamp memmemSCMTOHANDLEd champ

117:

118: Description des primitives C

119: define NBCPRIM

120: define FIRSTCPRIM

121: define NBCPRIM

122: define FIRSTCPRIM FIRSTCPRIM NBCPRIM

123: define NBCPRIM

124: define FIRSTCPRIM FIRSTCPRIM NBCPRIM

125: define NBCPRIM

126: define FIRSTCPRIM FIRSTCPRIM NBCPRIM

127: define APPLYCPRIMNO

128:

129: Variables du module Scheme compile

130: extern int bytecodelen

131: extern unsigned char bytecode

132: extern int constdesclen

133: extern unsigned char constdesc

134: extern int nbscmglobs

135: extern int scmglobs

136:

137: Prototypes de bitc

138: void allocheapint taille

139: int isallocatedint d

140: void markitint d

141: void gcint size

142: int alloccellint len int bitpattern

143: int predbooleanint d

144: int predpairint d

145: int consint car int cdr

146: int carint p

147: int cdrint p

148: int setcarint p int d

149: int setcdrint p int d

150: int listcopyint l

151: int predcharint d

152: int integertocharint n

153: int chartointegerint c

154: int cpredstringint d

155: int predstringint d

156: int cmakestringint len

157: int makestringint len

158: char findstringbaseint s int pos

159: int cstringrefint s int pos

160: int stringrefint s int pos

161: void cstringsetint s int pos int c

ANNEXE A SOURCES DU SYSTEME

162: int stringsetint s int pos int c

163: int stringlengthint s

164: int stringlentointstringlenint len

165: int cstringintlenint s

166: int toscmstringchar cs int len

167: int cstringequalint s int s

168: int stringequalint s int s

169: int stringcopyint s

170: int predsymbolint d

171: void stretchsymbolvectorvoid

172: int makesymbolint nom

173: int symboltostringint s

174: int stringtosymbolint string

175: int prednumberint d

176: int tocnumberint n

177: int cppoeint n int n

178: int cplusint n int n

179: int cmoinsint n int n

180: int cfoisint n int n

181: int cdiviseint n int n

182: int cpredvectorint d

183: int predvectorint d

184: int cmakevectorint len

185: int makevectorint len

186: int findvectorlocationint v int pos

187: int cvectorrefint v int pos

188: int vectorrefint v int pos

189: void cvectorsetint v int pos int val

190: int vectorsetint v int pos int val

191: int vectorlengthint v

192: int vectorlentointvectorlenint len

193: int cvectorintlenint v

194: int predprocedureint d

195: int makeclosureint entry int env

196: int closureentryint c

197: int closureenvint c

198: int applyint c int args

199: int cpredcontint d

200: int makecontvoid

201: void setcontpcint k int dest

202: void restorecontint k

203: int llinputvoid

204: int cpeekcharvoid

205: int peekcharvoid

206: int creadcharvoid

207: int readcharvoid

208: int writecharint c

209: int eqint d int d

210: int quitvoid

211: int returncurrentcontinuationvoid

212: int returntherewiththisint completecont int val

213: int introspectionint arg

214: void initbcreadervoid

215: int readbcbytevoid

216: int readbcintvoid

217: int getframeint step

218: int getvarint frame int offset

219: void setvarint frame int offset int val

220: void makenormalframeint size

221: void makerestframeint size

222: void pushargint arg

223: int popargvoid

224: void popnargsint n

225: int applycprimint cprimno int args

226: int applyclosureint c int args

227: void capplyint c int args

228: void executebcvoid

229: int initscmglobint code

230: int initscmglobint code

231: int mainint argc char argv

A noyauc

1: Mini interprete Scheme Troisieme dune serie

2: Ne traite pas

3: les ports

4: les points flottants

5: les entiers de taille illimitee

6: lentree de nombres nondecimaux

7:

8: include noyauh

9:

10:

11:

12:

13: Variables globales C

14:

15: int mem

16: int memlen nbhandles nbobj handle memnext memfree memstack

17: int gcmark gccompact gcratio gctime gctrav gcvecting gccut

18: int gcold gcnew gclen gcsrc gcdst gcstate

19:

20: int nbsymbols

21:

22: int evalpc

23:

24: int cprimNBCPRIMvoid

25:

26: peekchar

27: readchar

28: quit

29: returncurrentcontinuation

30:

31:

32: int cprimNBCPRIMint

33:

34: predboolean

35: predpair

36: car

37: cdr

38: predchar

39: integertochar

40: chartointeger

41: predstring

42: makestring

43: stringlength

44: stringcopy

45: predsymbol

46: symboltostring

47: stringtosymbol

48: prednumber

49: predvector

50: makevector

51: vectorlength

ANNEXE A SOURCES DU SYSTEME

52: predprocedure

53: writechar

54: introspection

55:

56:

57: int cprimNBCPRIMint int

58:

59: cons

60: setcar

61: setcdr

62: stringref

63: stringequal

64: cppoe

65: cplus

66: cmoins

67: cfois

68: cdivise

69: vectorref

70: apply

71: eq

72: returntherewiththis

73:

74:

75: int cprimNBCPRIMint int int

76:

77: stringset

78: vectorset

79:

80:

81:

82:

83:

84: Variables globales SCM

85:

86: Les variables contenues dans stack

87: doivent etre mises a jour par le gc

88: int globsNBGLOBS

89:

90:

91:

92:

93: Allocation du monceau

94:

95: void allocheapint taille

96:

97: int j

98:

99: memlen taille

100: mem mallocmemlen sizeof int

101: if mem NULL

102:

103: fprintfstderr Incapable dallouer le monceaun

104: exit

105:

106: nbhandles memlen

107: nbobj

108: handle

109: for j jnbhandles j

110: memj j

111: memnbhandles

112: memnext nbhandles

113: memfree memlen memnext

114: gcmark FALSE

115: gccompact FALSE

116: gcratio

117: gctime

118: gcvecting FALSEVAL

119: gcstate

120:

121:

122:

123:

124:

125: Garbage collector

126:

127: int isallocatedint d

128:

129: return CPREDNUMBERd CPREDSPECIALd

130:

131:

132: void markitint d

133:

134: if isallocatedd

135: return

136: if ISMARKEDd

137: return

138: memmemSCMTOHANDLEd GCMARK

139: memstack

140: memmemstack d

141:

142:

143: La description des etats est ailleurs

144: Note memfree nest maintenu quentre deux phases de GC

145: Note meme chose pour nbobj

146: void gcint size

147:

148: int court start j nbcases marque d handle subnlen

149:

150: gctime size size Simuler une multiplication rapide

151: if gcratio

152:

153: gctime size

154: if gcratio

155:

156: gctime size

157: if gcratio

158: gctime size gcratio

159:

160:

161:

162: while gctime

163: switch gcstate

164:

165: case

166:

167: if memfree

168: gcratio memlen

169: else

170: gcratio memnext nbhandles

171: nbobj

172: nbscmglobs

173: memfree

174: memfree

175: gctime size gcratio Car le ratio etait insuffisant

176: gctime gcratio

177: gcratio memfree

178: memnext nbhandles

179: nbobj

ANNEXE A SOURCES DU SYSTEME

180: nbscmglobs

181: gcratio

182: gctime Securite

183: gcstate

184: break

185:

186: case

187:

188: memstack memlen

189: gcmark TRUE

190: gccut

191: gcstate

192: break

193:

194: case

195:

196: nbcases nbscmglobs gccut gctime

197: nbscmglobs gccut

198: gctime

199: for jgccut jgccutnbcases j

200: markitscmglobsj

201: gctime nbcases

202: gccut nbcases

203: gcstate gccut nbscmglobs

204: break

205:

206: case

207:

208: if memstack memlen

209: gcstate

210: else

211:

212: gctrav memmemstack

213: memstack

214: gcsrc memSCMTOHANDLEgctrav

215: switch gctrav TYPEMASK

216:

217: case TYPEPAIR PAIR

218:

219: start

220: gclen

221: break

222:

223: case TYPECLOS CLOSURE

224:

225: start

226: gclen

227: break

228:

229: default

230:

231: subnlen memgcsrc

232: if subnlen CONTMASK CONT

233:

234: start

235: gclen

236:

237: else if subnlen VECTINGMASK STRING

238:

239: start

240: stringlentointstringlensubnlen

241: gclen start

242:

243: else VECTOR

244:

245: gclen

246: vectorlentointvectorlensubnlen

247: gccut

248: gctime

249: gcstate

250: goto label

251:

252:

253:

254: for jstart jgclen j

255: markitmemgcsrc j

256: gctime gclen

257: gcstate

258:

259: label

260: break

261:

262: case

263:

264: nbcases gclen gccut gctime gclen gccut gctime

265: for j jnbcases j

266: markitmemgcsrc gccut j

267: gctime nbcases

268: gccut nbcases

269: gcstate gccut gclen

270: break

271:

272: case

273:

274: for j jNBGLOBS j

275: markitglobsj

276: gcstate memstack memlen

277: break

278:

279: case

280:

281: gcmark FALSE

282: gccompact TRUE

283: gcsrc nbhandles

284: gcdst nbhandles

285: gcstate

286: nbobj

287: break

288:

289: case

290:

291: gcstate gcsrc memnext

292: break

293:

294: case

295:

296: d memgcsrc

297: marque d GCMARK

298: d GCMARK

299: memgcsrc d

300: switchd TYPEMASK

301:

302: case TYPEPAIR PAIR

303: case TYPECLOS CLOSURE

304:

305: court TRUE

306: gclen

307: break

ANNEXE A SOURCES DU SYSTEME

308:

309: default

310:

311: subnlen memgcsrc

312: if subnlen CONTMASK CONT

313:

314: court TRUE

315: gclen

316: break

317:

318: else if subnlen VECTINGMASK STRING

319:

320: court FALSE

321: gclen

322: stringlentointstringlensubnlen

323: break

324:

325: else VECTOR

326:

327: court FALSE

328: gclen

329: vectorlentointvectorlensubnlen

330: break

331:

332:

333:

334: handle SCMTOHANDLEd

335: if marque

336:

337: memhandle handle

338: handle handle

339: gctime gclen

340: gcsrc gclen

341: gcstate

342:

343: else if court

344:

345: memhandle gcdst

346: for j jgclen j

347: memgcdst j memgcsrc j

348: nbobj

349: gctime gclen

350: gcsrc gclen

351: gcdst gclen

352: gcstate

353:

354: else

355:

356: memhandle gcdst

357: memgcdst memgcsrc

358: memgcdst memgcsrc

359: nbobj

360: gctime

361: gcvecting d

362: gccut

363: gcold gcsrc

364: gcnew gcdst

365: gcdst gclen

366: gcstate

367:

368: break

369:

370: case

371:

372: nbcases gclen gccut gctime gclen gccut gctime

373: for j jnbcases j

374: memgcnew gccut j memgcold gccut j

375: gctime nbcases

376: gccut nbcases

377: if gccut gclen

378:

379: gcvecting scmfalse

380: gcsrc gclen

381: gcstate

382:

383: else

384: gcstate

385: break

386:

387: case

388:

389: memnext gcdst

390: printfs d cases pour d objets ratio de d reste dn

391: GC completed memnext nbhandles

392: nbobj gcratio memfree

393: memfree memlen memnext nbobj

394: gccompact FALSE

395: gcratio

396: gctime

397: gcstate

398: if memfree size

399:

400: fprintfstderr Manque de memoiren

401: exit

402:

403: break

404:

405:

406:

407:

408:

409:

410:

411: Fonction dallocation de memoire

412:

413: Un appel a cette fonction peut declencher le gc

414: int alloccellint len int bitpattern

415:

416: int j pos handle d marque

417:

418: gclen

419:

420: if gccompact

421:

422: if gcdst len gcsrc

423:

424: pos gcdst

425: gcdst len

426: marque

427:

428: else

429:

430: pos memnext

431: memnext len

432: marque GCMARK

433:

434:

435: else

ANNEXE A SOURCES DU SYSTEME

436:

437: pos memnext

438: memnext len

439: marque

440:

441:

442: handle handle

443: handle memhandle

444: memhandle pos

445:

446: d handle bitpattern

447:

448: mempos d marque

449:

450: return d

451:

452:

453:

454:

455:

456: Fonctions relatives a BOOLEAN

457:

458: int predbooleanint d

459:

460: return CPREDBOOLEANd scmtrue scmfalse

461:

462:

463:

464:

465:

466: Fonctions relatives a PAIR

467:

468: int predpairint d

469:

470: return CPREDPAIRd scmtrue scmfalse

471:

472:

473: int consint car int cdr

474:

475: int handle cell pair

476:

477: conscar car

478: conscdr cdr

479: pair alloccell TYPEPAIR

480: handle SCMTOHANDLEpair

481: cell memhandle

482: memcell conscar

483: memcell conscdr

484: return pair

485:

486:

487: int carint p

488:

489: return CHAMPp

490:

491:

492: int cdrint p

493:

494: return CHAMPp

495:

496:

497: int setcarint p int d

498:

499: if gcmark ISMARKEDp

500: markitd

501: CHAMPp d

502: return scmtrue

503:

504:

505: int setcdrint p int d

506:

507: if gcmark ISMARKEDp

508: markitd

509: CHAMPp d

510: return scmtrue

511:

512:

513: int listcopyint l

514:

515: int temp

516:

517: if l scmempty

518: return l

519: else

520:

521: listcopyl l

522: listcopycourant listcopytete conscarlistcopyl scmempty

523: listcopyl cdrlistcopyl

524: while listcopyl scmempty

525:

526: temp conscarlistcopyl scmempty

527: setcdrlistcopycourant temp

528: listcopyl cdrlistcopyl

529: listcopycourant cdrlistcopycourant

530:

531: return listcopytete

532:

533:

534:

535:

536:

537:

538: Fonctions relatives a CHAR

539:

540: int predcharint d

541:

542: return CPREDCHARd scmtrue scmfalse

543:

544:

545: int integertocharint n

546:

547: return TOSCMCHARtocnumbern

548:

549:

550: int chartointegerint c

551:

552: return TOSCMNUMBERTOCCHARc

553:

554:

555:

556:

557:

558: Fonctions relatives a STRING

559:

560: int cpredstringint d

561:

562: return CPREDOTHERd

563: memmemSCMTOHANDLEd VECTINGMASK STRINGVAL

ANNEXE A SOURCES DU SYSTEME

564:

565:

566: int predstringint d

567:

568: return cpredstringd scmtrue scmfalse

569:

570:

571: int cmakestringint len

572:

573: int intlen handle cell string

574:

575: intlen stringlentointstringlenlen

576: string alloccell intlen TYPEOTHER

577: handle SCMTOHANDLEstring

578: cell memhandle

579: memcell len STRINGVAL

580: return string

581:

582:

583: int makestringint len

584:

585: return cmakestringtocnumberlen

586:

587:

588: char findstringbaseint s int pos

589:

590: int intpos

591:

592: if s gcvecting

593: return char memmemSCMTOHANDLEs

594: else

595:

596: intpos pos LOGCPI

597: if intpos gccut

598: return char memgcold

599: else

600: return char memgcnew

601:

602:

603:

604: int cstringrefint s int pos

605:

606: char base

607:

608: base findstringbases pos

609: return int base pos

610:

611:

612: int stringrefint s int pos

613:

614: return TOSCMCHARcstringrefs tocnumberpos

615:

616:

617: void cstringsetint s int pos int c

618:

619: char base

620:

621: base findstringbases pos

622: base pos char c

623:

624:

625: int stringsetint s int pos int c

626:

627: cstringsets tocnumberpos TOCCHARc

628: return scmtrue

629:

630:

631: int stringlengthint s

632:

633: return TOSCMNUMBERCSTRINGLENs

634:

635:

636: int stringlentointstringlenint len

637:

638: int intlen

639:

640: intlen len CHARSPERINT LOGCPI

641: return intlen intlen

642:

643:

644: int cstringintlenint s

645:

646: return stringlentointstringlenCSTRINGLENs

647:

648:

649: int toscmstringchar cs int len

650:

651: int i scms

652:

653: scms cmakestringlen

654: for i ilen i

655: cstringsetscms i csi

656: return scms

657:

658:

659: int cstringequalint s int s

660:

661: int len len i

662:

663: len CSTRINGLENs

664: len CSTRINGLENs

665:

666: if len len

667: return FALSE

668:

669: for i ilen i

670: if cstringrefs i cstringrefs i

671: return FALSE

672: return TRUE

673:

674:

675: int stringequalint s int s

676:

677: return cstringequals s scmtrue scmfalse

678:

679:

680: int stringcopyint s

681:

682: int len i

683: int s

684:

685: len CSTRINGLENs

686: stringcopys s

687: s cmakestringlen

688: for i ilen i

689: cstringsets i cstringrefstringcopys i

690: return s

691:

ANNEXE A SOURCES DU SYSTEME

692:

693:

694:

695:

696: Fonctions relatives a SYMBOL

697:

698: int predsymbolint d

699:

700: return CPREDSYMBOLd scmtrue scmfalse

701:

702:

703: void stretchsymbolvectorvoid

704:

705: int oldlen newlen j

706: int newnames

707:

708: oldlen CVECTORLENscmsymbolnames

709: newlen oldlen

710: newnames cmakevectornewlen

711: for j jnbsymbols j

712: cvectorsetnewnames j cvectorrefscmsymbolnames j

713: scmsymbolnames newnames

714:

715:

716: Cette fonction ne doit etre utilisee

717: que par stringsymbol

718: int makesymbolint nom

719:

720: int numero

721:

722: if nbsymbols CVECTORLENscmsymbolnames

723: stretchsymbolvector

724:

725: numero nbsymbols

726: nbsymbols

727: cvectorsetscmsymbolnames numero nom

728:

729: return NUMBERTOSYMBOLnumero

730:

731:

732: int symboltostringint s

733:

734: return cvectorrefscmsymbolnames SYMBOLNUMBERs

735:

736:

737: int stringtosymbolint string

738:

739: int j

740:

741: for j jnbsymbols j

742: if cstringequalstring cvectorrefscmsymbolnames j

743: return NUMBERTOSYMBOLj

744:

745: return makesymbolstringcopystring

746:

747:

748:

749:

750:

751: Fonctions relatives a NUMBER

752:

753: int prednumberint d

754:

755: return CPREDNUMBERd scmtrue scmfalse

756:

757:

758: int tocnumberint n

759:

760: if n

761: return n BITH

762: else

763: return n

764:

765:

766: Les op se font AVEC les tags

767: int cppoeint n int n

768:

769: return n n scmtrue scmfalse

770:

771:

772: int cplusint n int n

773:

774: return n n NUMVAL

775:

776:

777: int cmoinsint n int n

778:

779: return n n NUMVAL

780:

781:

782: int cfoisint n int n

783:

784: return TOSCMNUMBERtocnumbern tocnumbern

785:

786:

787: int cdiviseint n int n

788:

789: return TOSCMNUMBERtocnumbern tocnumbern

790:

791:

792:

793:

794:

795: Fonctions relatives a VECTOR

796:

797: int cpredvectorint d

798:

799: return CPREDOTHERd

800: memmemSCMTOHANDLEd VECTINGMASK VECTORVAL

801:

802:

803: int predvectorint d

804:

805: return cpredvectord scmtrue scmfalse

806:

807:

808: int cmakevectorint len

809:

810: int intlen j

811: int cell handle vector

812:

813: intlen vectorlentointvectorlenlen

814: vector alloccell intlen TYPEOTHER

815: handle SCMTOHANDLEvector

816: cell memhandle

817: memcell len VECTORVAL

818: for j jintlen j

819: memcell j scmfalse

ANNEXE A SOURCES DU SYSTEME

820: return vector

821:

822:

823: int makevectorint len

824:

825: return cmakevectortocnumberlen

826:

827:

828: int findvectorlocationint v int pos

829:

830: if v gcvecting

831: return memSCMTOHANDLEv

832: else if pos gccut

833: return gcold

834: else

835: return gcnew

836:

837:

838: int cvectorrefint v int pos

839:

840: int location

841:

842: location findvectorlocationv pos

843: return memlocation pos

844:

845:

846: int vectorrefint v int pos

847:

848: return cvectorrefv tocnumberpos

849:

850:

851: void cvectorsetint v int pos int val

852:

853: int location

854:

855: if gcmark ISMARKEDv

856: markitval

857: location findvectorlocationv pos

858: memlocation pos val

859:

860:

861: int vectorsetint v int pos int val

862:

863: cvectorsetv tocnumberpos val

864: return scmtrue

865:

866:

867: int vectorlengthint v

868:

869: return TOSCMNUMBERCVECTORLENv

870:

871:

872: int vectorlentointvectorlenint len

873:

874: return len len

875:

876:

877: int cvectorintlenint v

878:

879: return vectorlentointvectorlenCVECTORLENv

880:

881:

882:

883:

884:

885: Fonctions relatives a PROCEDURE

886:

887: int predprocedureint d

888:

889: return CPREDCPRIMd CPREDCLOSUREd scmtrue scmfalse

890:

891:

892: int makeclosureint entry int env

893:

894: int cell handle closure

895:

896: makeclosenv env

897: closure alloccell TYPECLOS

898: handle SCMTOHANDLEclosure

899: cell memhandle

900: memcell entry

901: memcell makeclosenv

902: return closure

903:

904:

905: int closureentryint c

906:

907: return CHAMPc

908:

909:

910: int closureenvint c

911:

912: return CHAMPc

913:

914:

915: Cette fonction ne peut appeler direct capply

916: Note elle utilise le applyhook a la fin du bytecode

917: int applyint c int args

918:

919: evalpc bytecodelen

920: evalargs consc args

921: return scmfalse

922:

923:

924:

925:

926:

927: Fonctions relatives a CONT

928:

929: int cpredcontint d

930:

931: return CPREDOTHERd

932: memmemSCMTOHANDLEd CONTMASK CONTVAL

933:

934:

935: int makecontvoid

936:

937: int cell handle k

938:

939: k alloccell TYPEOTHER

940: handle SCMTOHANDLEk

941: cell memhandle

942: memcell PCTOPCTAGevalpc

943: memcell evalenv

944: memcell evalargs

945: memcell evalcont

946: return k

947:

ANNEXE A SOURCES DU SYSTEME

948:

949: void setcontpcint k int dest

950:

951: CHAMPk PCTOPCTAGdest

952:

953:

954: void restorecontint k

955:

956: int cell

957:

958: cell memSCMTOHANDLEk

959: evalpc PCTAGTOPCmemcell

960: evalenv memcell

961: evalargs memcell

962: evalcont memcell

963:

964:

965:

966:

967:

968: Fonctions dentreesortie

969:

970: int llinputvoid

971:

972: int c

973:

974: c getchar

975: if c EOF

976:

977: printfEOFnQuitn

978: exit

979:

980: return c

981:

982:

983: static int lookahead

984: static int lookaheadvalide

985:

986: int cpeekcharvoid

987:

988: if lookaheadvalide

989:

990: lookahead llinput

991: lookaheadvalide TRUE

992:

993: return lookahead

994:

995:

996: int peekcharvoid

997:

998: return TOSCMCHARcpeekchar

999:

1000:

1001: int creadcharvoid

1002:

1003: if lookaheadvalide

1004:

1005: lookaheadvalide FALSE

1006: return lookahead

1007:

1008: else

1009: return llinput

1010:

1011:

1012: int readcharvoid

1013:

1014: return TOSCMCHARcreadchar

1015:

1016:

1017: int writecharint c

1018:

1019: printfc TOCCHARc

1020: return scmtrue

1021:

1022:

1023:

1024:

1025:

1026: Autres fonctions de la librairie

1027:

1028: int eqint d int d

1029:

1030: return d d scmtrue scmfalse

1031:

1032:

1033: int quitvoid

1034:

1035: printfQuitn

1036: exit

1037:

1038:

1039: int returncurrentcontinuationvoid

1040:

1041: int temp

1042:

1043: temp makecont

1044: return constemp evalprevargs

1045:

1046:

1047: int returntherewiththisint completecont int val

1048:

1049: evalprevargs cdrcompletecont

1050: restorecontcarcompletecont

1051: return val

1052:

1053:

1054:

1055:

1056:

1057: Fonctions relatives au coeur de linterprete

1058:

1059: static int introstate

1060:

1061: int introspectionint arg

1062:

1063: if introstate

1064:

1065: introstate

1066: return scmconstants

1067:

1068: else

1069:

1070: scmconstants arg

1071: return scmfalse

1072:

1073:

1074:

1075:

ANNEXE A SOURCES DU SYSTEME

1076:

1077:

1078: Le coeur de linterprete

1079:

1080: void initbcreadervoid

1081:

1082: evalpc

1083: return

1084:

1085:

1086: int readbcbytevoid

1087:

1088: int b

1089:

1090: b int bytecodeevalpc

1091: evalpc

1092: return b

1093:

1094:

1095: int readbcintvoid

1096:

1097: int msb

1098:

1099: msb readbcbyte

1100: return msb readbcbyte

1101:

1102:

1103: int getframeint step

1104:

1105: int frame

1106:

1107: frame evalenv

1108: while step

1109:

1110: if CPREDPAIRframe

1111: frame carframe

1112: else

1113: frame cvectorrefframe

1114: step

1115:

1116: return frame

1117:

1118:

1119: int getvarint frame int offset

1120:

1121: int f

1122:

1123: f getframeframe

1124: if CPREDPAIRf

1125: return cdrf

1126: else

1127: return cvectorreff offset

1128:

1129:

1130: void setvarint frame int offset int val

1131:

1132: int f

1133:

1134: f getframeframe

1135: if CPREDPAIRf

1136: setcdrf val

1137: else

1138: cvectorsetf offset val

1139:

1140:

1141: void makenormalframeint size

1142:

1143: int pos

1144: int larg frame

1145:

1146: if size

1147: evalenv consevalenv carevalargs

1148: else

1149:

1150: frame cmakevectorsize

1151: cvectorsetframe evalenv

1152: larg evalargs

1153: for pos possize pos

1154:

1155: cvectorsetframe pos carlarg

1156: larg cdrlarg

1157:

1158: evalenv frame

1159:

1160:

1161:

1162: void makerestframeint size

1163:

1164: int pos

1165: int larg

1166: int temp

1167:

1168: if size

1169:

1170: temp listcopyevalargs

1171: evalenv consevalenv temp

1172:

1173: else

1174:

1175: makerestframeframe cmakevector size

1176: cvectorsetmakerestframeframe evalenv

1177: larg evalargs

1178: for pos possize pos

1179:

1180: cvectorsetmakerestframeframe pos carlarg

1181: larg cdrlarg

1182:

1183: temp listcopylarg

1184: cvectorsetmakerestframeframe size temp

1185: evalenv makerestframeframe

1186:

1187:

1188:

1189: void pushargint arg

1190:

1191: evalargs consarg evalargs

1192:

1193:

1194: int popargvoid

1195:

1196: int temp

1197:

1198: temp carevalargs

1199: evalargs cdrevalargs

1200: return temp

1201:

1202:

1203: void popnargsint n

ANNEXE A SOURCES DU SYSTEME

1204:

1205: int i

1206:

1207: for i in i

1208: poparg

1209:

1210:

1211: int applycprimint cprimno int args

1212:

1213: int arg arg arg

1214:

1215: if cprimno FIRSTCPRIM

1216: return cprimcprimno

1217: arg carargs

1218: if cprimno FIRSTCPRIM

1219: return cprimcprimno FIRSTCPRIMarg

1220: args cdrargs

1221: arg carargs

1222: if cprimno FIRSTCPRIM

1223: return cprimcprimno FIRSTCPRIMarg arg

1224: args cdrargs

1225: arg carargs

1226: return cprimcprimno FIRSTCPRIMarg arg arg

1227:

1228:

1229: int applyclosureint c int args

1230:

1231: evalpc closureentryc

1232: evalargs args

1233: evalenv closureenvc

1234: return scmfalse

1235:

1236:

1237: void capplyint c int args

1238:

1239: int cprimno

1240: int temp

1241:

1242: if CPREDCPRIMc Dans une application generale

1243: il faut forcer la restoration

1244: cprimno CPRIMNUMBERc

1245: temp applycprimcprimno args

1246: if cprimno APPLYCPRIMNO

1247:

1248: restorecontevalcont

1249: pushargtemp

1250:

1251:

1252: else

1253: applyclosurec args

1254:

1255:

1256: void executebcvoid

1257:

1258: int op dest frameno offsetno

1259: int frame

1260: int readbcinfovoid

1261:

1262: initbcreader

1263: while TRUE

1264:

1265: op readbcbyte

1266: switch op

1267:

1268: case

1269:

1270: readbcinfo readbcbyte

1271: goto label

1272:

1273: case

1274:

1275: readbcinfo readbcint

1276: label

1277: pushargcvectorrefscmconstants readbcinfo

1278: break

1279:

1280: case

1281:

1282: readbcinfo readbcbyte

1283: goto label

1284:

1285: case

1286:

1287: readbcinfo readbcint

1288: label

1289: frame getframereadbcinfo

1290: if CPREDPAIRframe

1291: evalval cdrframe

1292: else

1293: evalval cvectorrefframe readbcinfo

1294: pushargevalval

1295: break

1296:

1297: case

1298:

1299: readbcinfo readbcbyte

1300: goto label

1301:

1302: case

1303:

1304: readbcinfo readbcint

1305: label

1306: pushargscmglobsreadbcinfo

1307: break

1308:

1309: case

1310:

1311: readbcinfo readbcbyte

1312: goto label

1313:

1314: case

1315:

1316: readbcinfo readbcint

1317: label

1318: frame getframereadbcinfo

1319: evalval poparg

1320: if CPREDPAIRframe

1321: setcdrframe evalval

1322: else

1323: cvectorsetframe readbcinfo evalval

1324: pushargscmfalse

1325: break

1326:

1327: case

1328:

1329: readbcinfo readbcbyte

1330: goto label

1331:

ANNEXE A SOURCES DU SYSTEME

1332: case

1333:

1334: readbcinfo readbcint

1335: label

1336: evalval poparg

1337: if gcmark

1338: markitevalval

1339: scmglobsreadbcinfo evalval

1340: pushargscmfalse

1341: break

1342:

1343: case

1344:

1345: evalval makeclosureevalpc evalenv

1346: restorecontevalcont

1347: pushargevalval

1348: break

1349:

1350: case

1351:

1352: dest readbcint

1353: if poparg scmfalse

1354: evalpc dest

1355: break

1356:

1357: case

1358:

1359: setcontpcevalcont evalpc

1360: continue to

1361:

1362: case

1363:

1364: evalenv scmempty

1365: continue to

1366:

1367: case

1368:

1369: evalpc readbcint

1370: break

1371:

1372: case

1373:

1374: evalval evalargs

1375: restorecontevalcont

1376: setcdrevalval evalargs

1377: evalargs evalval

1378: break

1379:

1380: case

1381:

1382: evalprevargs consevalargs evalprevargs

1383: continue to

1384:

1385: case

1386:

1387: evalargs scmempty

1388: break

1389:

1390: case

1391:

1392: fprintfstderr Ce nest plus suppose etre utilisen

1393: break

1394:

1395: case

1396:

1397: setcontpcevalcont evalpc

1398: continue to

1399:

1400: case

1401:

1402: capplycarevalargs cdrevalargs

1403: break

1404:

1405: case

1406:

1407: fprintfstderr Ce nest plus suppose etre utilisen

1408: break

1409:

1410: case

1411:

1412: readbcinfo readbcbyte

1413: goto label

1414:

1415: case

1416:

1417: readbcinfo readbcint

1418: label

1419: makenormalframereadbcinfo

1420: break

1421:

1422: case

1423:

1424: readbcinfo readbcbyte

1425: goto label

1426:

1427: case

1428:

1429: readbcinfo readbcint

1430: label

1431: makerestframereadbcinfo

1432: break

1433:

1434: case

1435:

1436: return

1437: break

1438:

1439: case

1440:

1441: evalval evalargs

1442: evalargs carevalprevargs

1443: evalprevargs cdrevalprevargs

1444: setcdrevalval evalargs

1445: evalargs evalval

1446: break

1447:

1448: case

1449:

1450: pushargscmempty

1451: break

1452:

1453: case

1454:

1455: pushargscmfalse

1456: break

1457:

1458: case

1459:

ANNEXE A SOURCES DU SYSTEME

1460: pushargscmtrue

1461: break

1462:

1463: case

1464:

1465: pushargTOSCMCHARreadbcbyte

1466: break

1467:

1468: case

1469:

1470: readbcinfo readbcbyte

1471: goto label

1472:

1473: case

1474:

1475: readbcinfo readbcbyte

1476: goto label

1477:

1478: case

1479:

1480: readbcinfo readbcint

1481: label

1482: pushargTOSCMNUMBERreadbcinfo

1483: break

1484:

1485: case

1486:

1487: readbcinfo readbcint

1488: label

1489: pushargTOSCMNUMBERreadbcinfo

1490: break

1491:

1492: case

1493:

1494: evalenv getframe

1495: break

1496:

1497: case

1498:

1499: frameno

1500: offsetno

1501: goto label

1502:

1503: case

1504:

1505: frameno

1506: offsetno

1507: goto label

1508:

1509: case

1510:

1511: frameno

1512: offsetno

1513: goto label

1514:

1515: case

1516:

1517: frameno

1518: offsetno

1519: goto label

1520:

1521: case

1522:

1523: frameno

1524: offsetno

1525: goto label

1526:

1527: case

1528:

1529: frameno

1530: offsetno

1531: label

1532: pusharggetvarframeno offsetno

1533: break

1534:

1535: case

1536:

1537: makenormalframe

1538: break

1539:

1540: case

1541:

1542: makenormalframe

1543: break

1544:

1545: case

1546:

1547: makerestframe

1548: break

1549:

1550: case

1551:

1552: evalcont makecont

1553: evalargs scmempty

1554: break

1555:

1556: case

1557:

1558: fprintfstderr Ce nest plus suppose etre utilisen

1559: break

1560:

1561: case

1562:

1563: dest readbcint

1564: pushargmakeclosureevalpc evalenv

1565: evalpc dest

1566: break

1567:

1568: case

1569:

1570: readbcinfo readbcbyte

1571: goto label

1572:

1573: case

1574:

1575: readbcinfo readbcint

1576: label

1577: popnargsreadbcinfo

1578: break

1579:

1580: case

1581:

1582: poparg

1583: break

1584:

1585: case

1586:

1587: setcontpcevalcont evalpc

ANNEXE A SOURCES DU SYSTEME

1588: continue to

1589:

1590: case

1591:

1592: readbcinfo readbcbyte

1593: goto label

1594:

1595: case

1596:

1597: setcontpcevalcont evalpc

1598: continue to

1599:

1600: case

1601:

1602: readbcinfo readbcint

1603: label

1604: dest scmglobsreadbcinfo

1605: capplydest evalargs

1606: break

1607:

1608: default

1609:

1610: pushargapplycprim op evalargs

1611: break

1612:

1613:

1614:

1615:

1616:

1617:

1618:

1619:

1620: Le programme principal

1621:

1622: int initscmglobint code

1623:

1624: if code Sans valeur initiale

1625: return scmfalse

1626: else if code Cprim

1627: return CMAKECPRIM code

1628: else Fermeture

1629: return TOSCMNUMBERcode

1630:

1631:

1632: int initscmglobint code

1633:

1634: int entry

1635:

1636: if CPREDNUMBERcode

1637:

1638: entry code Et non pas tocnumbercode

1639: return makeclosureentry scmempty

1640:

1641: else

1642: return code

1643:

1644:

1645: int mainint argc char argv

1646:

1647: int i

1648:

1649: if LOGCPI CHARSPERINT

1650:

1651: fprintfstderr Verifier LOGCPI

1652: exit

1653:

1654:

1655: allocheapDEFAULTHEAPSIZE

1656:

1657: Attention lordre est important GC scmfalse etc

1658: scmfalse FALSEVAL

1659: for i iNBGLOBS i

1660: globsi scmfalse

1661: scmempty NULLVAL

1662: scmtrue TRUEVAL

1663: evalprevargs scmempty

1664:

1665: for i inbscmglobs i Temporairement

1666: scmglobsi initscmglobscmglobsi

1667:

1668: nbsymbols

1669: scmsymbolnames cmakevector

1670: scmconstants toscmstringconstdesc constdesclen

1671:

1672: for i inbscmglobs i

1673: scmglobsi initscmglobscmglobsi

1674:

1675: introstate

1676: lookaheadvalide FALSE

1677:

1678: executebc

1679: return

1680:

1681:

1682: Ajuster la limite de taille du bytecode dans analysescm

ANNEXE A SOURCES DU SYSTEME

A Le chier de librairie

Tel que decrit a la section le chier de librairie se divise en quatre parties declaration

des fonctions primitives denition des fonctions nonstandard cachees denition des fonctions

nonstandard visibles denition des fonctions standard

1:

2: Fonctions implantees dans le noyau Pour savoir lesquelles

3: sont visibles voir sections plus bas

4:

5:

6: peekchar

7: readchar

8: quit

9: returncurrentcontinuation

10: boolean

11: pair

12: car

13: cdr

14: char

15: integerchar

16: charinteger

17: string

18: makestring

19: stringlength

20: stringcopy

21: symbol

22: symbolstring

23: stringsymbol

24: number

25: vector

26: makevector

27: vectorlength

28: procedure

29: writechar

30: introspection

31: cons

32: setcar

33: setcdr

34: stringref

35: string

36: cppoe

37: cplus

38: cmoins

39: cfois

40: cdivise

41: vectorref

42: apply

43: eq

44: returntherewiththis

45: stringset

46: vectorset

47:

48: f Fin des definitions des primitives C

49:

50:

51: Fonctions cachees de la librairie

52:

53:

54: define foldl

55: lambda binop start l

56: if null l

57: start

58: foldl binop binop start car l cdr l

59: define foldl

60: lambda binop l

61: if null cdr l

62: car l

63: foldl binop cons binop car l cadr l

64: cddr l

65: define foldr

66: lambda binop l

67: if null cdr l

68: car l

69: binop car l foldr binop cdr l

70:

71: define genericmember

72: lambda releq obj list

73: if null list

74: f

75: if releq car list obj

76: list

77: genericmember releq obj cdr list

78:

79: define genericassoc

80: lambda releq obj alist

81: cond null alist

82: f

83: releq car car alist obj

84: car alist

85: else

86: genericassoc releq obj cdr alist

87:

88: define math

89: lambda x y

90: if math x y math y x f

91:

92: define math

93: lambda x y

94: not math y x

95:

96: define math

97: lambda x y

98: not math x y

99:

100: define math cppoe

101:

102: define math lambda x y math y x

103:

104: define genericcompare

105: lambda binrel l

106: if null cddr l

107: binrel car l cadr l

108: and binrel car l cadr l

109: genericcompare binrel cdr l

110:

111: define max lambda x y if x y x y

ANNEXE A SOURCES DU SYSTEME

112: define min lambda x y if x y x y

113:

114: define math cplus

115:

116: define math cfois

117:

118: define math cmoins

119:

120: define math cdivise

121:

122: define math

123: lambda num den

124: math num math den math num den

125:

126: define mathgcd

127: lambda n n

128: let loop n abs n n abs n

129: cond zero n n

130: zero n n

131: else

132: let grand max n n

133: petit min n n

134: loop petit modulo grand petit

135:

136: define mathlcm

137: lambda n n

138: cond zero n abs n

139: zero n abs n

140: else

141: let n abs n

142: n abs n

143: n n mathgcd n n

144:

145: define stringcompare

146: lambda rel rel s s

147: let len stringlength s

148: len stringlength s

149: len min len len

150: let loop pos

151: if pos len

152: let c stringref s pos

153: c stringref s pos

154: cond rel c c

155:

156: rel c c

157: loop pos

158: else

159:

160: cond len len

161:

162: len len

163:

164: else

165:

166:

167: define map

168: lambda f l

169: if null l

170: l

171: cons f car l map f cdr l

172:

173: define writemanychars

174: lambda l

175: foreach writechar l

176:

177: define writecdr

178: lambda d parent

179: cond eq d

180: writechar

181: pair d

182: writechar space

183: parent car d

184: writecdr cdr d parent

185: else

186: writemanychars space space

187: parent d

188: writechar

189:

190: define writevector

191: lambda d parent

192: let len vectorlength d

193: writemanychars

194: if len

195: begin

196: parent vectorref d

197: let loop pos

198: if pos len

199: begin

200: writechar space

201: parent vectorref d pos

202: loop pos

203: writechar

204:

205: define makebytereader

206: lambda s

207: let pos

208: lambda

209: let c stringref s pos

210: set pos pos

211: c

212: define makenumberreader

213: lambda readconstbyte

214: lambda

215: let msc readconstbyte

216: lsc readconstbyte

217: msb charinteger msc

218: lsb charinteger lsc

219: msb lsb

220: define readconstdesc

221: lambda constv pos readconstbyte readconstnumber

222: let type readconstbyte

223: cond

224: char type EMPTY

225:

226: char type PAIR

227: let incar vectorref constv readconstnumber

228: incdr vectorref constv readconstnumber

229: cons incar incdr

230: char type BOOLEAN

231: char readconstbyte t

232: char type CHAR

233: readconstbyte

234: char type STRING

235: let len readconstnumber

236: s makestring len

237: let loop pos

238: if pos len

239: begin

ANNEXE A SOURCES DU SYSTEME

240: stringset s pos readconstbyte

241: loop pos

242: s

243: char type SYMBOL

244: stringsymbol vectorref constv readconstnumber

245: char type NUMBER

246: let sign readconstbyte

247: valabs readconstnumber

248: if char sign

249: valabs

250: valabs

251: char type VECTOR

252: let len readconstnumber

253: v makevector len

254: let loop pos

255: if pos len

256: begin

257: vectorset v pos vectorref constv readconstnumber

258: loop pos

259: v

260: define extracttopconst

261: lambda constv readconstnumber

262: let nbtop readconstnumber

263: topv makevector nbtop

264: let loop pos

265: if pos nbtop

266: begin

267: vectorset topv pos vectorref constv readconstnumber

268: loop pos

269: topv

270:

271: f Fin des definitions des fonctions internes

272:

273:

274: Les fonctions nonstandard mais visibles tout

275: de meme pour les programmes compiles

276:

277:

278: define append

279: lambda l l

280: if null l

281: l

282: let tete cons car l l

283: let loop cur tete l cdr l

284: if null l

285: tete

286: begin

287: setcdr cur cons car l l

288: loop cdr cur cdr l

289:

290: quit

291:

292: define makepromise

293: lambda proc

294: let resultready f

295: result f

296: lambda

297: if resultready

298: result

299: let x proc

300: if resultready

301: result

302: begin set resultready t

303: set result x

304: result

305:

306: Note tres importante cette fonction sert a reconstituer les constantes

307: du programme avant le debut de son execution Toute fonction appelee

308: durant lexecution de celleci ne doit pas comporter de constantes etant

309: donne quelles ne sont pas encore baties

310: define installconst

311: lambda

312: let conststring introspection f Porte secrete

313: readconstbyte makebytereader conststring

314: readconstnumber makenumberreader readconstbyte

315: nbconst readconstnumber

316: constv makevector nbconst

317: let loop pos

318: if pos nbconst

319: begin

320: vectorset constv

321: pos

322: readconstdesc constv

323: pos

324: readconstbyte

325: readconstnumber

326: loop pos

327: let topv extracttopconst constv readconstnumber

328: introspection topv Porte secrete

329:

330: f Fin des definitions des fonctions nonstandard visibles

331:

332:

333: Debut des fonctions Scheme standard de la librairie

334:

335:

336:

337: define not lambda x if x f t

338: boolean

339:

340:

341: define eqv

342: lambda d d

343: cond and number d number d

344: d d

345: and char d char d

346: char d d

347: else

348: eq d d

349: eq

350: define equal

351: lambda d d

352: cond eqv d d

353: t

354: and pair d pair d

355: and equal car d car d equal cdr d cdr d

356: and vector d vector d

357: let len vectorlength d

358: if not len vectorlength d

359: f

360: let loop pos

361: cond pos len

362: t

363: equal vectorref d pos vectorref d pos

364: loop pos

365: else

366: f

367: and string d string d

ANNEXE A SOURCES DU SYSTEME

368: string d d

369: else

370: f

371:

372:

373: pair

374: cons

375: car

376: cdr

377: setcar

378: setcdr

379: define caar lambda p car car p

380: define cadr lambda p car cdr p

381: define cdar lambda p cdr car p

382: define cddr lambda p cdr cdr p

383: define caaar lambda p caar car p

384: define caadr lambda p caar cdr p

385: define cadar lambda p cadr car p

386: define caddr lambda p cadr cdr p

387: define cdaar lambda p cdar car p

388: define cdadr lambda p cdar cdr p

389: define cddar lambda p cddr car p

390: define cdddr lambda p cddr cdr p

391: define caaaar lambda p caaar car p

392: define caaadr lambda p caaar cdr p

393: define caadar lambda p caadr car p

394: define caaddr lambda p caadr cdr p

395: define cadaar lambda p cadar car p

396: define cadadr lambda p cadar cdr p

397: define caddar lambda p caddr car p

398: define cadddr lambda p caddr cdr p

399: define cdaaar lambda p cdaar car p

400: define cdaadr lambda p cdaar cdr p

401: define cdadar lambda p cdadr car p

402: define cdaddr lambda p cdadr cdr p

403: define cddaar lambda p cddar car p

404: define cddadr lambda p cddar cdr p

405: define cdddar lambda p cdddr car p

406: define cddddr lambda p cdddr cdr p

407: define null

408: lambda x eq x

409: define list

410: lambda l

411: cond null l

412: t

413: not pair l

414: f

415: else

416: let loop slow l fast cdr l phase

417: cond null fast

418: t

419: not pair fast

420: f

421: eq slow fast

422: f

423: phase

424: loop slow cdr fast

425: else

426: loop cdr slow cdr fast

427: define list lambda l l

428: define length

429: lambda l

430: let loop l l len

431: if null l

432: len

433: loop cdr l len

434: define append

435: lambda ll

436: foldr append cons ll

437: define reverse

438: lambda l

439: let loop l l rl

440: if null l

441: rl

442: loop cdr l cons car l rl

443: define listtail

444: lambda l pos

445: if pos

446: l

447: listtail cdr l pos

448: define listref lambda l pos car listtail l pos

449: define memq

450: lambda obj list

451: genericmember eq obj list

452: define memv

453: lambda obj list

454: genericmember eqv obj list

455: define member

456: lambda obj list

457: genericmember equal obj list

458: define assq lambda obj alist genericassoc eq obj alist

459: define assv lambda obj alist genericassoc eqv obj alist

460: define assoc lambda obj alist genericassoc equal obj alist

461:

462:

463: symbol

464: symbolstring

465: stringsymbol

466:

467:

468: number

469: define complex number

470: define real number

471: define rational number

472: define integer number

473: define exact lambda n t

474: define inexact lambda n f

475: define lambda l genericcompare math l

476: define lambda l genericcompare math l

477: define lambda l genericcompare math l

478: define lambda l genericcompare math l

479: define lambda l genericcompare math l

480: define zero lambda n n

481: define positive lambda n n

482: define negative lambda n n

483: define odd lambda n math abs n

484: define even lambda n math abs n

485: define max lambda l foldl max l

486: define min lambda l foldl min l

487: define lambda l foldl math l

488: define lambda l foldl math l

489: define lambda l if null cdr l math car l foldl math l

490: define

491: lambda l if null cdr l quotient car l foldl quotient l

492: define abs lambda n if negative n n n

493: define quotient

494: lambda n d

495: if d

ANNEXE A SOURCES DU SYSTEME

496:

497: if n

498: if d

499: math n d

500: math n d

501: if d

502: math n d

503: math n d

504: define remainder lambda n d n d quotient n d

505: define modulo

506: lambda n d

507: if d

508: n

509: if d

510: if n

511: remainder n d

512: remainder remainder n d d d

513: modulo n d

514: define gcd lambda l foldl mathgcd l

515: define lcm lambda l foldl mathlcm l

516: define numerator lambda q q

517: define denominator lambda q

518: define floor numerator

519: define ceiling numerator

520: define truncate numerator

521: define round numerator

522: define rationalize lambda x y x

523: define sqrt

524: lambda x

525: cond not positive x

526:

527: x

528:

529: else

530: let loop sous sur x

531: if sur sous

532: sous

533: let new sous sur

534: if new new x

535: loop new sur

536: loop sous new

537: define expt

538: lambda base exp

539: if not positive exp

540:

541: let facteur if odd exp base

542: reste expt base base exp

543: facteur reste

544: define exactinexact lambda z z

545: define inexactexact lambda z z

546: define numberstring

547: lambda n lradix

548: let radix if null lradix car lradix

549: negative negative n

550: absn abs n

551: if n

552: stringcopy

553: letrec decomp lambda n digits

554: if n

555: digits

556: decomp n radix

557: cons modulo n radix digits

558: let ndad lambda n

559: if n

560: n charinteger

561: n charinteger a

562: digits decomp absn

563: adigits map ndad digits

564: cdigits map integerchar adigits

565: signedchars if negative

566: cons cdigits

567: cdigits

568: liststring signedchars

569: define stringnumber

570: lambda str lradix

571: let radix if null lradix car lradix

572: maxnum if radix

573: integerchar radix charinteger

574:

575: len stringlength str

576: letrec checkdigit

577: lambda d

578: if radix

579: and char d char d maxnum

580: or and char d char d maxnum

581: and char a chardowncase d

582: char chardowncase d f

583: checksyntax

584: lambda min pos

585: if pos len

586: pos min

587: let d stringref str pos

588: cond checkdigit d

589: checksyntax min pos

590: or char d char d

591: and pos checksyntax

592: else f

593: recomp lambda acc digits

594: if null digits

595: acc

596: recomp acc radix car digits

597: cdr digits

598: cdnd lambda c

599: if charnumeric c

600: charinteger c charinteger

601: charinteger chardowncase c

602: charinteger a

603:

604: and checksyntax

605: let signedchars stringlist str

606: negative char car signedchars

607: positive char car signedchars

608: cdigits if or negative positive

609: cdr signedchars

610: signedchars

611: digits map cdnd cdigits

612: absn recomp digits

613: if negative absn absn

614:

615:

616: char

617: define char lambda c c charinteger c charinteger c

618: define char lambda c c not char c c

619: define char lambda c c not char c c

620: define char lambda c c charinteger c charinteger c

621: define char lambda c c char c c

622: define charci

623: lambda c c char chardowncase c chardowncase c

ANNEXE A SOURCES DU SYSTEME

624: define charci

625: lambda c c char chardowncase c chardowncase c

626: define charci

627: lambda c c char chardowncase c chardowncase c

628: define charci

629: lambda c c char chardowncase c chardowncase c

630: define charci

631: lambda c c char chardowncase c chardowncase c

632: define charalphabetic

633: lambda c and charci a c charci c z

634: define charnumeric lambda c and char c char c

635: define charwhitespace

636: lambda c

637: or char c space

638: char c integerchar Tab

639: char c newline

640: char c integerchar FF

641: char c integerchar CR

642: define charuppercase lambda c and char A c char c Z

643: define charlowercase lambda c and char a c char c z

644: charinteger

645: integerchar

646: define charupcase

647: lambda c

648: if charlowercase c

649: integerchar charinteger c

650: charinteger A charinteger a

651: c

652: define chardowncase

653: lambda c

654: if charuppercase c

655: integerchar charinteger c

656: charinteger a charinteger A

657: c

658:

659:

660: string

661: define makestring

662: lambda len lfill

663: let str makestring len

664: if not null lfill

665: stringfill str car lfill

666: str

667: define string lambda l liststring l

668: stringlength

669: stringref

670: stringset

671: string

672: define string

673: lambda s s stringcompare char char s s

674: define string

675: lambda s s stringcompare char char s s

676: define string

677: lambda s s stringcompare char char s s

678: define string

679: lambda s s stringcompare char char s s

680: define stringci

681: lambda s s stringcompare charci charci s s

682: define stringci

683: lambda s s stringcompare charci charci s s

684: define stringci

685: lambda s s stringcompare charci charci s s

686: define stringci

687: lambda s s stringcompare charci charci s s

688: define stringci

689: lambda s s stringcompare charci charci s s

690: define substring

691: lambda str start end

692: let len end start

693: newstr makestring len

694: let loop pos

695: if pos len

696: begin

697: stringset newstr pos stringref str start pos

698: loop pos

699: newstr

700: define stringappend

701: lambda ls

702: let llen map stringlength ls

703: totlen foldl llen

704: newstring makestring totlen

705: iter lambda iter ls llen from to

706: if to totlen

707: if from car llen

708: begin

709: stringset newstring

710: to

711: stringref car ls from

712: iter iter ls llen from to

713: iter iter cdr ls cdr llen to

714: iter iter ls llen

715: newstring

716: define stringlist

717: lambda str

718: let loop pos stringlength str l

719: if pos

720: l

721: loop pos cons stringref str pos l

722: define liststring

723: lambda l

724: let len length l

725: newstring makestring len

726: iter lambda iter l to

727: if to len

728: begin

729: stringset newstring to car l

730: iter iter cdr l to

731: iter iter l

732: newstring

733: stringcopy

734: define stringfill

735: lambda str fill

736: let loop pos stringlength str

737: if pos

738: begin

739: stringset str pos fill

740: loop pos

741:

742:

743: vector

744: define makevector

745: lambda len lfill

746: let v makevector len

747: if not null lfill

748: vectorfill v car lfill

749: v

750: define vector lambda l listvector l

751: vectorlength

ANNEXE A SOURCES DU SYSTEME

752: vectorref

753: vectorset

754: define vectorlist

755: lambda v

756: let loop pos vectorlength v l

757: if pos

758: l

759: loop pos cons vectorref v pos l

760: define listvector

761: lambda l

762: let len length l

763: v makevector len

764: let loop l l pos

765: if not null l

766: begin

767: vectorset v pos car l

768: loop cdr l pos

769: v

770: define vectorfill

771: lambda v fill

772: let loop pos vectorlength v

773: if pos

774: begin

775: vectorset v pos fill

776: loop pos

777:

778:

779: procedure

780: define apply

781: lambda proc llargs

782: let largs if null cdr llargs

783: car llargs

784: foldr cons llargs

785: apply proc largs

786: define map

787: lambda proc ll

788: if null car ll

789:

790: let tetes map car ll

791: queues map cdr ll

792: cons apply proc tetes

793: apply map cons proc queues

794: define foreach

795: lambda proc ll

796: if null car ll

797: f

798: let tetes map car ll

799: queues map cdr ll

800: apply proc tetes

801: apply foreach cons proc queues

802: define force lambda promise promise

803: define callwithcurrentcontinuation

804: lambda proc

805: let cc returncurrentcontinuation

806: if vector cc

807: vectorref cc

808: let escapeproc lambda val

809: let v vector val

810: returntherewiththis cc v

811: proc escapeproc

812: define callcc callwithcurrentcontinuation

813:

814:

815: readchar

816: peekchar

817: define write

818: lambda d

819: cond eq d f

820: writemanychars f

821: eq d t

822: writemanychars t

823: symbol d

824: apply writemanychars stringlist symbolstring d

825: eqv d space

826: writemanychars s p a c e

827: eqv d newline

828: writemanychars n e w l i n e

829: char d

830: writemanychars d

831: vector d

832: writevector d write

833: pair d

834: writechar

835: write car d

836: writecdr cdr d write

837: number d

838: apply writemanychars stringlist numberstring d

839: string d

840: writechar

841: let len stringlength d

842: let loop pos

843: if pos len

844: let c stringref d pos

845: cond char c

846: writemanychars loop pos

847: char c

848: writemanychars loop pos

849: else

850: writechar c

851: writechar

852: procedure d

853: writemanychars p r o c e d u r e

854: null d

855: writemanychars

856: else

857: f

858: define display

859: lambda d

860: cond char d

861: writechar d

862: vector d

863: writevector d display

864: pair d

865: writechar

866: display car d

867: writecdr cdr d display

868: string d

869: apply writemanychars stringlist d

870: else

871: write d

872: define newline lambda writechar newline

873: writechar

874:

875: f Fin des definitions des fonctions standard

ANNEXE A SOURCES DU SYSTEME

A Le compilateur vers du co deo ctets

Les dierentes phases de la compilation sont autant que p ossible implantees dans le meme

ordre quelles sont executees

1: Les fonctions utilitaires generales

2:

3: Suppose que les deux arguments sont deja des ensembles de symboles

4: define symbolsetunion

5: lambda ss ss

6: cond null ss

7: ss

8: memq car ss ss

9: symbolsetunion cdr ss ss

10: else

11: cons car ss symbolsetunion cdr ss ss

12:

13: define symbolsetintersection

14: lambda ss ss

15: cond null ss

16:

17: memq car ss ss

18: cons car ss symbolsetintersection cdr ss ss

19: else

20: symbolsetintersection cdr ss ss

21:

22: define foldr

23: lambda binop start l

24: if null l

25: start

26: binop car l foldr binop start cdr l

27:

28: define foldr

29: lambda binop l

30: if null cdr l

31: car l

32: binop car l foldr binop cdr l

33:

34: define filter

35: lambda pred l

36: cond null l

37: pred car l cons car l filter pred cdr l

38: else filter pred cdr l

39:

40: define formalsvarlist

41: lambda formals

42: cond symbol formals

43: list formals

44: null formals

45:

46: else

47: cons car formals formalsvarlist cdr formals

48:

49: define prefix

50: lambda s s

51: let l stringlength s

52: l stringlength s

53: if l l

54: f

55: let loop i

56: cond i l

57: t

58: char stringref s i stringref s i

59: loop i

60: else

61: f

62:

63: define unprefix

64: lambda s s

65: let l stringlength s

66: cond l stringlength s

67: stringappend s a

68: char a stringref s l

69: stringappend s b

70: else

71: stringappend s a

72:

73:

74:

75:

76: Initialiser les variables globales du programme

77:

78: define initglobvars

79: lambda

80: set safenamememv memv

81: set safenamemakepromise makepromise

82: set safenamelistvector listvector

83: set safenamelist list

84: set safenameappend append

85: set safenamecons cons

86: set gensympref f

87: set gensymnumber

88: set libcprims f

89: set libalias f

90: set libclos f

91: set libpublics f

92: set libnames f

93: set applycprimno f

94: set dirreq f

95: set allreq f

96: set reqclosnodes f

97: set constcounter

98: set constalist

99: set topcounter

100: set topalist

101: set constdescstring f

102: set globcounter

103: set globhidden

104: set globpublic

105: set globsource

106: set globv

107: set globvlen

108: set physglobno

109: set programbytecode f

110: set labelcounter

111: set labelv

112: set labelvlen

113: set flatprogrambytecode f

114: set finalprogrambytecode f

ANNEXE A SOURCES DU SYSTEME

115: set globvarinitcodes f

116:

117:

118:

119:

120: Lire le programme source

121:

122: define readsource

123: lambda name

124: let port openinputfile name

125: let loop

126: let exp read port

127: if eofobject exp

128: begin

129: closeinputport port

130:

131: cons exp loop

132:

133:

134:

135:

136: Trouver des noms pour memv makepromise listvector list

137: append et cons De cette facon transcase cie plus loin

138: pourront inserer un symbole representant une fonction

139: du systeme aux endroits generes par les macrosexpansion

140:

141: define safenamememv memv

142: define safenamemakepromise makepromise

143: define safenamelistvector listvector

144: define safenamelist list

145: define safenameappend append

146: define safenamecons cons

147:

148: Cette fonction ne fonctionne que pour les struc noncirc

149: define findallsymbols

150: lambda d

151: cond symbol d

152: list d

153: pair d

154: symbolsetunion findallsymbols car d

155: findallsymbols cdr d

156: vector d

157: let loop pos vectorlength d

158: if pos

159:

160: symbolsetunion findallsymbols vectorref d pos

161: loop pos

162: else

163:

164:

165: Trouver un prefixe unique pour avoir un gensym correct

166: define finduniqprefix

167: lambda ss

168: let loop pref names map symbolstring ss

169: if null names

170: pref

171: let name car names

172: if prefix pref name

173: loop unprefix pref name cdr names

174: loop pref cdr names

175:

176: La fonction gensym

177: define gensympref f

178: define gensymnumber

179:

180: define gensym

181: lambda

182: let strnum numberstring gensymnumber

183: symname stringappend gensympref strnum

184: sym stringsymbol symname

185: set gensymnumber gensymnumber

186: sym

187:

188:

189:

190:

191: Traduction des expressions Scheme en expressions plus simples

192: Il ne reste que des references de var des quotes des literaux

193: sevaluant a euxmemes des appels de procedure des lambda exp

194: des if des set des begins des defines se rapportant a des

195: var glob uniquement

196:

197: A ne pas inserer dans la liste des translators

198: define transdefine

199: lambda l

200: if symbol cadr l

201: l

202: let procname caadr l

203: formals cdadr l

204: exps cddr l

205: define procname lambda formals exps

206:

207: A ne pas inserer dans la liste des translators

208: define flattenbegin

209: lambda expbegin

210: cons begin

211: let loop l cdr expbegin flat

212: if null l

213: flat

214: let tete car l

215: queue cdr l

216: if and pair tete eq car tete begin

217: loop cdr tete loop queue flat

218: cons tete loop queue flat

219:

220: A ne pas inserer dans la liste des translators

221: define extractdefine

222: lambda lexp

223: let tete car lexp

224: reste cdr lexp

225: if and pair tete eq car tete define

226: let result extractdefine reste

227: cons cons tete car result cdr result

228: cons lexp

229:

230: A ne pas inserer dans la liste des translators

231: define transbody

232: lambda l

233: let flatbody flattenbegin l

234: result extractdefine cdr flatbody

235: rawdefines car result

236: exps cdr result

237: defines map transdefine rawdefines

238: decls map cdr defines

239: body begin exps

240: if null decls

241: body

242: letrec decls body

ANNEXE A SOURCES DU SYSTEME

243:

244: A ne pas inserer dans la liste des translators

245: define translambda

246: lambda l

247: list lambda

248: cadr l

249: transbody cons begin cddr l

250:

251: A ne pas inserer dans la liste des translators

252: define transbegin

253: lambda l

254: let flat flattenbegin l

255: if null cddr flat

256: cadr flat

257: flat

258:

259: A ne pas inserer dans la liste des translators

260: define transnormallet

261: lambda l

262: let bindings cadr l

263: body cddr l

264: vars map car bindings

265: inits map cadr bindings

266: lambda vars body inits

267:

268: A ne pas inserer dans la liste des translators

269: define transletloop

270: lambda l

271: let loopname cadr l

272: bindings caddr l

273: body cdddr l

274: vars map car bindings

275: inits map cadr bindings

276: letrec loopname lambda vars body

277: loopname

278: inits

279:

280: define translet

281: lambda l

282: if symbol cadr l

283: transletloop l

284: transnormallet l

285:

286: define translet

287: lambda l

288: let bindings cadr l

289: body cddr l

290: if or null bindings null cdr bindings

291: let bindings body

292: let prem car bindings

293: reste cdr bindings

294: let prem let reste body

295:

296: define transletrec

297: lambda l

298: let bindings cadr l

299: body cddr l

300: if null bindings

301: let body

302: let vars map car bindings

303: inits map cadr bindings

304: falsebind map lambda v v f vars

305: sets map lambda v i set v i vars inits

306: let falsebind

307: sets

308: let body

309:

310: define transand

311: lambda l

312: cond null cdr l

313: t

314: null cddr l

315: cadr l

316: else

317: if cadr l and cddr l f

318:

319: define transor

320: lambda l

321: cond null cdr l

322: f

323: null cddr l

324: cadr l

325: else

326: let ehd cadr l

327: etl cddr l

328: tmp gensym

329: let tmp ehd

330: if tmp

331: tmp

332: or etl

333:

334: define transcond

335: lambda l

336: if null cdr l

337: f

338: let clause cadr l

339: autres cddr l

340: newcond cons cond autres

341: cond eq car clause else

342: cons begin cdr clause

343: null cdr clause

344: list or car clause newcond

345: eq cadr clause

346: let test car clause

347: recipient caddr clause

348: tmp gensym

349: let tmp test

350: if tmp

351: recipient tmp

352: newcond

353: else

354: let test car clause

355: actions cdr clause

356: conseq cons begin actions

357: if test conseq newcond

358:

359: define transcase

360: lambda l

361: let tmpkey gensym

362: transtest

363: lambda test

364: if eq test else else safenamememv tmpkey test

365: key cadr l

366: clauses cddr l

367: tests map car clauses

368: exprlists map cdr clauses

369: memvtests map transtest tests

370: condclauses map cons memvtests exprlists

ANNEXE A SOURCES DU SYSTEME

371: let tmpkey key cond condclauses

372:

373: define transdo

374: lambda l

375: let normalizestep lambda v sf

376: if null sf v car sf

377: bindings cadr l

378: testnsequence caddr l

379: commands cdddr l

380: vars map car bindings

381: inits map cadr bindings

382: stepsfac map cddr bindings

383: steps map normalizestep vars stepsfac

384: test car testnsequence

385: sequence cdr testnsequence

386: loopvar gensym

387: loopcall cons loopvar steps

388: loopbindings map list vars inits

389: let loopvar loopbindings

390: if test

391: begin

392: f

393: sequence

394: begin

395: commands

396: loopcall

397:

398: define transdelay

399: lambda exp

400: let delexp cadr exp

401: safenamemakepromise lambda delexp

402:

403: A ne pas inclure dans la liste des translators

404: define detectunquote

405: lambda exp level

406: cond vector exp

407: let loop pos vectorlength exp

408: cond pos

409: f

410: detectunquote vectorref exp pos level

411: t

412: else

413: loop pos

414: pair exp

415: let tete car exp

416: cond eq tete quasiquote

417: detectunquote cadr exp level

418: or eq tete unquote eq tete unquotesplicing

419: if level

420: t

421: detectunquote cadr exp level

422: else

423: or detectunquote tete level

424: detectunquote cdr exp level

425: else

426: f

427:

428: define transquasiquote

429: lambda l

430: let loop exp cadr l level

431: cond not detectunquote exp level

432: list quote exp

433: vector exp

434: list safenamelistvector

435: loop vectorlist exp level

436: pair exp

437: let tete car exp

438: cond eq tete quasiquote

439: list safenamelist

440: quasiquote

441: loop cadr exp level

442: eq tete unquote

443: if level

444: cadr exp

445: list safenamelist

446: unquote

447: loop cadr exp level

448: and pair tete

449: eq car tete unquotesplicing

450: level

451: if null cdr exp

452: cadr tete

453: list safenameappend

454: cadr tete

455: loop cdr exp level

456: eq tete unquotesplicing

457: list safenamelist

458: unquotesplicing

459: loop cadr exp level

460: else

461: list safenamecons

462: loop car exp level

463: loop cdr exp level

464:

465: define translators

466: list cons let translet

467: cons let translet

468: cons letrec transletrec

469: cons and transand

470: cons or transor

471: cons cond transcond

472: cons case transcase

473: cons do transdo

474: cons delay transdelay

475: cons quasiquote transquasiquote

476:

477: define transsub

478: lambda exp

479: if or boolean exp

480: symbol exp

481: char exp

482: number exp

483: string exp

484: exp

485: let tete car exp

486: cond eq tete quote

487: exp

488: eq tete lambda

489: let newlambda translambda exp

490: list lambda

491: cadr newlambda

492: transsub caddr newlambda

493: eq tete if

494: cons if map transsub cdr exp

495: eq tete set

496: list set cadr exp transsub caddr exp

497: eq tete begin

498: transbegin cons begin map transsub cdr exp

ANNEXE A SOURCES DU SYSTEME

499: eq tete define

500: let newdefine transdefine exp

501: list define

502: cadr newdefine

503: transsub caddr newdefine

504: else

505: let ass assq tete translators

506: if ass

507: transsub cdr ass exp

508: let newexp map transsub exp

509: if and pair car newexp

510: eq caar newexp lambda

511: null cadar newexp

512: caddar newexp

513: newexp

514:

515:

516:

517:

518: Operations sur les nodes

519:

520: define makectenode

521: lambda cte vector cte f

522: define makerefnode

523: lambda symbol vector symbol f f f

524: define makerefnodefull

525: lambda symbol loc val glob vector symbol loc val glob

526: define makelambdanode

527: lambda formals body vector formals f body f

528: define makeifnode

529: lambda test conseq altern vector test conseq altern

530: define makesetnode

531: lambda symbol exp vector symbol f exp f

532: define makebeginnode

533: lambda lexp vector lexp

534: define makedefnode

535: lambda symbol exp vector symbol f exp

536: define makecallnode

537: lambda op larg vector op larg

538: define makeglobdescnode

539: lambda symbol lib nbaff vector symbol lib nbaff f f f

540:

541: define nodetype

542: lambda node

543: vectorref node

544:

545: define ctenode lambda node nodetype node

546: define refnode lambda node nodetype node

547: define lambdanode lambda node nodetype node

548: define ifnode lambda node nodetype node

549: define setnode lambda node nodetype node

550: define beginnode lambda node nodetype node

551: define defnode lambda node nodetype node

552: define callnode lambda node nodetype node

553: define globdescnode lambda node nodetype node

554:

555: define getter lambda node vectorref node

556: define getter lambda node vectorref node

557: define getter lambda node vectorref node

558: define getter lambda node vectorref node

559: define getter lambda node vectorref node

560: define getter lambda node vectorref node

561:

562: define getcte getter

563: define getno getter

564: define getsymbol getter

565: define getloc getter

566: define getval getter

567: define getglob getter

568: define getformals getter

569: define getfdesc getter

570: define getbody getter

571: define getlabel getter

572: define gettest getter

573: define getconseq getter

574: define getaltern getter

575: define getexp getter

576: define getlexp getter

577: define getop getter

578: define getlarg getter

579: define getlib getter

580: define getnbaff getter

581: define getinit getter

582: define getlibno getter

583: define getsrcno getter

584:

585: define setter lambda node val vectorset node val

586: define setter lambda node val vectorset node val

587: define setter lambda node val vectorset node val

588: define setter lambda node val vectorset node val

589: define setter lambda node val vectorset node val

590: define setter lambda node val vectorset node val

591:

592: define setno setter

593: define setglob setter

594: define setloc setter

595: define setfdesc setter

596: define setnbaff setter

597: define setinit setter

598: define setop setter

599: define setval setter

600: define setlibno setter

601: define setsrcno setter

602: define setlabel setter

603:

604:

605:

606:

607: Transformation du code source en noeuds fonctionnels

608:

609: define lnode f

610:

611: define expnode

612: lambda exp

613: cond or boolean exp char exp number exp string exp

614: makectenode exp

615: symbol exp

616: makerefnode exp

617: else pair

618: let tete car exp

619: cond eq tete quote

620: makectenode cadr exp

621: eq tete lambda

622: makelambdanode cadr exp expnode caddr exp

623: eq tete if

624: makeifnode expnode cadr exp

625: expnode caddr exp

626: expnode

ANNEXE A SOURCES DU SYSTEME

627: if null cdddr exp f cadddr exp

628: eq tete set

629: makesetnode cadr exp expnode caddr exp

630: eq tete begin

631: makebeginnode map expnode cdr exp

632: eq tete define

633: makedefnode cadr exp expnode caddr exp

634: else procedure call

635: makecallnode expnode car exp

636: map expnode cdr exp

637:

638:

639:

640:

641: Ramassage des variables globales definies modifiees ou lues

642:

643: define extractglobnames

644: let actionv

645: vector

646: lambda node loop env cte

647:

648: lambda node loop env ref

649: let refsym getsymbol node

650: if memq refsym env

651:

652: list refsym

653: lambda node loop env lambda

654: loop getbody node

655: symbolsetunion env formalsvarlist

656: getformals node

657: lambda node loop env if

658: let testglobs loop gettest node env

659: conseqglobs loop getconseq node env

660: alternglobs loop getaltern node env

661: symbolsetunion symbolsetunion testglobs conseqglobs

662: alternglobs

663: lambda node loop env set

664: let setsym getsymbol node

665: l if memq setsym env list setsym

666: symbolsetunion l loop getexp node env

667: lambda node loop env begin

668: let lnode getlexp node

669: llglob map lambda node loop node env lnode

670: foldr symbolsetunion llglob

671: lambda node loop env def

672: symbolsetunion list getsymbol node

673: loop getexp node env

674: lambda node loop env call

675: let lnode cons getop node getlarg node

676: llglob map lambda node loop node env lnode

677: foldr symbolsetunion llglob

678: lambda node

679: let loop node node env

680: vectorref actionv nodetype node node loop env

681:

682:

683:

684:

685: Chargement de la librairie

686:

687: define libcprims f

688: define libalias f

689: define libclos f

690: define libpublics f

691: define libnames f

692: define applycprimno f

693:

694: define readlib

695: lambda libname

696: let port openinputfile libname

697: let loop n

698: if n

699: begin

700: closeinputport port

701:

702: let loop

703: let datum read port

704: if datum

705: let reste loop

706: cons cons datum car reste cdr reste

707: cons loop n

708:

709: define getlibcprims

710: lambda libpart

711: map lambda def

712: let name car def

713: no cdr def

714: if eq name apply

715: set applycprimno no

716: cons name no

717: libpart

718:

719: define getlibalias

720: lambda libpart libpart libpart

721: let defs append libpart libpart libpart

722: defals filter lambda def

723: and not symbol def

724: symbol caddr def

725: defs

726: map lambda defal cons cadr defal caddr defal defals

727:

728: define getlibclos

729: lambda libpart libpart libpart

730: let defs append libpart libpart libpart

731: defcls filter lambda def

732: and not symbol def

733: not symbol caddr def

734: defs

735: map lambda defcl cons cadr defcl caddr defcl defcls

736:

737: define getlibpublics

738: lambda libpart libpart

739: map lambda symordef

740: if symbol symordef

741: symordef

742: cadr symordef

743: append libpart libpart

744:

745: define getlibnames

746: lambda libpart libpart libpart libpart

747: let cprimnames map car libpart

748: defs append libpart libpart libpart

749: truedefs filter lambda def not symbol def defs

750: append cprimnames map cadr truedefs

751:

752: define loadlib

753: lambda

754: let alllib readlib librairiescm

ANNEXE A SOURCES DU SYSTEME

755: libpart listref alllib

756: libpart listref alllib

757: libpart listref alllib

758: libpart listref alllib

759: set libcprims getlibcprims libpart

760: set libalias getlibalias libpart libpart libpart

761: set libclos getlibclos libpart libpart libpart

762: set libpublics getlibpublics libpart libpart

763: set libnames getlibnames libpart libpart libpart libpart

764:

765:

766:

767:

768: Capture de la librairie necessaire

769:

770: define dirreq f

771: define allreq f

772: define reqclosnodes f

773:

774: define grablib

775: lambda dirreq

776: let loop toadd dirreq added closnodes

777: cond null toadd

778: set allreq added

779: set reqclosnodes closnodes

780: memq car toadd added

781: loop cdr toadd added closnodes

782: else

783: let newfun car toadd

784: asscprim assq newfun libcprims

785: if asscprim

786: loop cdr toadd

787: cons newfun added

788: closnodes

789: let assalias assq newfun libalias

790: if assalias

791: loop cons cdr assalias cdr toadd

792: cons newfun added

793: closnodes

794: let assclos assq newfun libclos

795: let code cdr assclos

796: subcode transsub code

797: node expnode subcode

798: nodeglobs extractglobnames node

799: newclos cons newfun node

800: loop append nodeglobs cdr toadd

801: cons newfun added

802: cons newclos closnodes

803:

804:

805:

806:

807: Ramassage et codage des constantes du programme source

808:

809: define constcounter

810: define constalist

811: Chaque ass original numero desc

812: define topcounter

813: define topalist

814: Chaque ass constno topconstno

815: define constdescstring f

816:

817: define constno

818: lambda d

819: let ass assoc d constalist

820: if ass

821: cadr ass

822: begin

823: cond or null d boolean d char d number d

824: set constalist

825: cons cons d cons constcounter d constalist

826: pair d

827: let leftno constno car d

828: rightno constno cdr d

829: desc cons leftno rightno

830: set constalist cons cons d cons constcounter desc

831: constalist

832: string d

833: set constalist

834: cons cons d cons constcounter d constalist

835: symbol d

836: let nom symbolstring d

837: nomno constno nom

838: desc stringsymbol numberstring nomno

839: set constalist cons cons d cons constcounter desc

840: constalist

841: vector d

842: let listd vectorlist d

843: listno map constno listd

844: desc listvector listno

845: set constalist cons cons d cons constcounter desc

846: constalist

847: set constcounter constcounter

848: constcounter

849:

850: define topconstno

851: lambda d

852: if or null d boolean d char d number d

853: f

854: let cno constno d

855: ass assv cno topalist

856: if ass

857: cdr ass

858: begin

859: set topalist cons cons cno topcounter topalist

860: set topcounter topcounter

861: topcounter

862:

863: define codeabsnumber

864: lambda n

865: let msb quotient n

866: lsb modulo n

867: msc integerchar msb

868: lsc integerchar lsb

869: string msc lsc

870:

871: define codeoneconst

872: lambda desc

873: cond null desc

874: pour EMPTY

875: pair desc

876: stringappend pour PAIR

877: codeabsnumber car desc

878: codeabsnumber cdr desc

879: boolean desc

880: if desc t f pour BOOLEAN

881: char desc

882: string desc pour CHAR

ANNEXE A SOURCES DU SYSTEME

883: string desc

884: stringappend pour STRING

885: codeabsnumber stringlength desc

886: desc

887: symbol desc

888: stringappend pour SYMBOL

889: codeabsnumber

890: stringnumber symbolstring desc

891: number desc

892: stringappend pour NUMBER

893: if desc

894: codeabsnumber abs desc

895: vector desc

896: let listref vectorlist desc

897: listcodes map codeabsnumber listref

898: listallcodes

899: cons pour VECTOR

900: cons codeabsnumber vectorlength desc

901: listcodes

902: apply stringappend listallcodes

903:

904: define codeinconst

905: lambda nbconst constalist

906: let rightalist reverse constalist

907: listdesc map cddr rightalist

908: listcodes map codeoneconst listdesc

909: listallcodes cons codeabsnumber nbconst listcodes

910: apply stringappend listallcodes

911:

912: define codetopconst

913: lambda nbtop topalist

914: let rightalist reverse topalist

915: listtop map car rightalist

916: listcodes map codeabsnumber listtop

917: listallcodes cons codeabsnumber nbtop listcodes

918: apply stringappend listallcodes

919:

920: define codeconst

921: lambda

922: stringappend codeinconst constcounter constalist

923: codetopconst topcounter topalist

924:

925:

926:

927:

928: Enregistrement des variables globales

929:

930: define globcounter

931: define globhidden Variables cachees de la librairie

932: define globpublic Variables visibles de la librairie

933: define globsource Variables introduites par le source

934: Chaque assoc nom numero

935: define globv

936: define globvlen

937:

938: define globvarno

939: lambda name lib

940: or

941: cond memq name libpublics

942: let ass assq name globpublic

943: if ass

944: cdr ass

945: let newass cons name globcounter

946: set globpublic cons newass globpublic

947: f

948: lib

949: let ass assq name globhidden

950: if ass

951: cdr ass

952: let newass cons name globcounter

953: set globhidden cons newass globhidden

954: f

955: else

956: let ass assq name globsource

957: if ass

958: cdr ass

959: let newass cons name globcounter

960: set globsource cons newass globsource

961: f

962: begin

963: if globcounter globvlen

964: let newlen globvlen

965: newv makevector newlen

966: let loop pos

967: if pos globvlen

968: begin

969: vectorset newv pos vectorref globv pos

970: loop pos

971: set globv newv

972: set globvlen newlen

973: vectorset globv globcounter makeglobdescnode name lib

974: set globcounter globcounter

975: globcounter

976:

977:

978:

979:

980: Localisation des variables

981:

982: Un resultat glob name signifie que name est globale

983: Un resultat lex frame offset donne le numero de frame et la

984: position sur ce frame

985: Un resultat lex frame f indique que name est seule sur son frame

986: define wherevar

987: lambda name env

988: if null env

989: cons glob name

990: let locals car env

991: membership memq name locals

992: if membership

993: let nblocals length locals

994: pos nblocals length membership

995: declpos if nblocals f pos

996: cons lex cons declpos

997: let result wherevar name cdr env

998: if eq car result glob

999: result

1000: let frame cadr result

1001: offset cddr result

1002: cons lex cons frame offset

1003:

1004:

1005:

1006:

1007: Parcours des noeuds pour

1008: Numeroter les constantes si nec

1009: Identifier chaque variable

1010: Compter les definitions et affectations des var glob

ANNEXE A SOURCES DU SYSTEME

1011: Resumer les parametres formels

1012:

1013: define traversectenode

1014: lambda node env lib

1015: setno node topconstno getcte node

1016:

1017: define traverserefnode

1018: lambda node env lib

1019: let name getsymbol node

1020: pos wherevar name env

1021: glob eq car pos glob

1022: loc if glob globvarno name lib cdr pos

1023: setglob node glob

1024: setloc node loc

1025:

1026: define formalsfdesc

1027: lambda formals

1028: let loop nbreq formals formals

1029: cond null formals

1030: cons nbreq f

1031: symbol formals

1032: cons nbreq t

1033: else

1034: loop nbreq cdr formals

1035:

1036: define traverselambdanode

1037: lambda node env lib

1038: let formals getformals node

1039: varlist formalsvarlist formals

1040: newenv if null varlist env cons varlist env

1041: fdesc formalsfdesc formals

1042: setfdesc node fdesc

1043: traversenode getbody node newenv lib

1044:

1045: define traverseifnode

1046: lambda node env lib

1047: traversenode gettest node env lib

1048: traversenode getconseq node env lib

1049: traversenode getaltern node env lib

1050:

1051: define traversesetnode

1052: lambda node env lib

1053: let name getsymbol node

1054: pos wherevar name env

1055: glob eq car pos glob

1056: loc if glob globvarno name lib cdr pos

1057: setglob node glob

1058: setloc node loc

1059: if glob

1060: let desc vectorref globv loc

1061: oldnb getnbaff desc

1062: setnbaff desc oldnb Declare la var mut

1063: traversenode getexp node env lib

1064:

1065: define traversebeginnode

1066: lambda node env lib

1067: let lnode getlexp node

1068: foreach lambda node traversenode node env lib lnode

1069:

1070: define traversedefnode

1071: lambda node env lib

1072: let loc globvarno getsymbol node lib

1073: desc vectorref globv loc

1074: oldnb getnbaff desc

1075: setloc node loc

1076: setnbaff desc oldnb

1077: traversenode getexp node env lib

1078:

1079: define traversecallnode

1080: lambda node env lib

1081: let lnode getlarg node

1082: traversenode getop node env lib

1083: foreach lambda node traversenode node env lib lnode

1084:

1085: define traversenode

1086: let actionv

1087: vector

1088: traversectenode

1089: traverserefnode

1090: traverselambdanode

1091: traverseifnode

1092: traversesetnode

1093: traversebeginnode

1094: traversedefnode

1095: traversecallnode

1096: lambda node env lib

1097: vectorref actionv nodetype node node env lib

1098:

1099: define traverse

1100: lambda

1101: foreach

1102: lambda name

1103: let no globvarno name t

1104: desc vectorref globv no

1105: setnbaff desc

1106: allreq

1107: foreach lambda node traversenode node t

1108: map cdr reqclosnodes

1109: foreach lambda node traversenode node f

1110: lnode

1111:

1112:

1113:

1114:

1115: Determiner la valeur initiale des fonctions de la librairie

1116:

1117: define findaninit

1118: lambda name

1119: let asscprim assq name libcprims

1120: if asscprim

1121: cons cprim cdr asscprim

1122: let assalias assq name libalias

1123: if assalias

1124: findaninit cdr assalias

1125: let node cdr assq name reqclosnodes

1126: if lambdanode node

1127: cons clos node

1128: begin

1129: display Error fonct de la lib a env nonvide

1130: write name

1131: newline

1132: cons clos

1133:

1134: define findinits

1135: lambda

1136: let loop no

1137: if no globcounter

1138: let desc vectorref globv no

ANNEXE A SOURCES DU SYSTEME

1139: if getlib desc

1140: let name getsymbol desc

1141: init findaninit name

1142: setinit desc init

1143: loop no

1144:

1145:

1146:

1147:

1148: Parcours des noeuds pour

1149: Resoudre a priori certaines references

1150: Inliner lorsque possible

1151:

1152: define reducelist

1153: append append

1154: math

1155: math

1156: math

1157: math

1158: math

1159: max max

1160: min min

1161: math

1162: math

1163: math

1164: quotient

1165: gcd mathgcd

1166: lcm mathlcm

1167: makestring makestring

1168: makevector makevector

1169: apply apply

1170: map map

1171:

1172: define reducedfunction

1173: lambda name nbargs

1174: let rule assq name reducelist

1175: if not rule

1176: f

1177: if nbargs cadr rule

1178: caddr rule

1179: f

1180:

1181: define optimizecall

1182: lambda node match

1183: let symbolfield match

1184: globfield t

1185: locfield globvarno match t

1186: vardesc vectorref globv locfield

1187: valfield getinit vardesc

1188: newop makerefnodefull symbolfield

1189: locfield

1190: valfield

1191: globfield

1192: setop node newop

1193:

1194: define reducecall

1195: lambda node

1196: let op getop node

1197: name getsymbol op

1198: nbargs length getlarg node

1199: match reducedfunction name nbargs

1200: if match optimizecall node match

1201:

1202: define traversectenode

1203: lambda node lib

1204: t

1205:

1206: define traverserefnode

1207: lambda node lib

1208: if getglob node

1209: setval node

1210: let vardesc vectorref globv getloc node

1211: varinit getinit vardesc

1212: if lib

1213: varinit

1214: if not getlib vardesc

1215: f

1216: if getnbaff vardesc

1217: f

1218: varinit

1219:

1220: define traverselambdanode

1221: lambda node lib

1222: traversenode getbody node lib

1223:

1224: define traverseifnode

1225: lambda node lib

1226: traversenode gettest node lib

1227: traversenode getconseq node lib

1228: traversenode getaltern node lib

1229:

1230: define traversesetnode

1231: lambda node lib

1232: traversenode getexp node lib

1233:

1234: define traversebeginnode

1235: lambda node lib

1236: foreach lambda node traversenode node lib

1237: getlexp node

1238:

1239: define traversedefnode

1240: lambda node lib

1241: traversenode getexp node lib

1242:

1243: define traversecallnode

1244: lambda node lib

1245: let op getop node

1246: traversenode op lib

1247: foreach lambda node traversenode node lib

1248: getlarg node

1249: if and refnode op getglob op getval op

1250: reducecall node

1251:

1252: define traversenode

1253: let actionv

1254: vector

1255: traversectenode

1256: traverserefnode

1257: traverselambdanode

1258: traverseifnode

1259: traversesetnode

1260: traversebeginnode

1261: traversedefnode

1262: traversecallnode

1263: lambda node lib

1264: vectorref actionv nodetype node node lib

1265:

1266: define traverse

ANNEXE A SOURCES DU SYSTEME

1267: lambda

1268: foreach lambda node traversenode node t

1269: map cdr reqclosnodes

1270: foreach lambda node traversenode node f

1271: lnode

1272:

1273:

1274:

1275:

1276: Assigner des numeros physiques aux variables

1277:

1278: define physglobno

1279:

1280: define genphysno

1281: lambda

1282: set physglobno physglobno

1283: physglobno

1284:

1285: define assignphysno

1286: lambda

1287: let loop no

1288: if no globcounter

1289: let desc vectorref globv no

1290: libvar getlib desc

1291: mutvar getnbaff desc

1292: cond not libvar

1293: let physno genphysno

1294: setlibno desc physno

1295: setsrcno desc physno

1296: mutvar

1297: setlibno desc genphysno

1298: setsrcno desc genphysno

1299: else

1300: let physno genphysno

1301: setlibno desc physno

1302: setsrcno desc physno

1303: loop no

1304:

1305:

1306:

1307:

1308: Gestion des labels

1309:

1310: define labelcounter

1311: define labelv

1312: define labelvlen

1313:

1314: define makelabel

1315: lambda

1316: if labelcounter labelvlen

1317: let newlen labelvlen

1318: newv makevector newlen

1319: let loop pos

1320: if pos labelcounter

1321: begin

1322: vectorset newv pos vectorref labelv pos

1323: loop pos

1324: set labelv newv

1325: set labelvlen newlen

1326: set labelcounter labelcounter

1327: labelcounter

1328:

1329:

1330:

1331:

1332: Generation du bytecode

1333:

1334: define programbytecode f

1335: define flatprogrambytecode f

1336: define finalprogrambytecode f

1337:

1338: define bcompileno

1339: lambda no

1340: let msb quotient no

1341: lsb modulo no

1342: list msb lsb

1343:

1344: define bcompilectenull pour

1345: lambda

1346:

1347:

1348: define bcompilecteboolean pour f pour t

1349: lambda b

1350: if b

1351:

1352: define bcompilectechar pour char

1353: lambda c

1354: list charinteger c

1355:

1356: define bcompilectenumber courts longs

1357: lambda n

1358: if n

1359: if n

1360: list n

1361: list bcompileno n

1362: if n

1363: list n

1364: list bcompileno n

1365:

1366: define bcompilecteimm

1367: lambda cte

1368: cond null cte

1369: bcompilectenull

1370: boolean cte

1371: bcompilecteboolean cte

1372: char cte

1373: bcompilectechar cte

1374: else

1375: bcompilectenumber cte

1376:

1377: define bcompilectebuilt

1378: lambda no

1379: if no

1380: list no

1381: list bcompileno no

1382:

1383: define bcompilecte

1384: lambda node tail lib

1385: let constno getno node

1386: getctebc if constno

1387: bcompilectebuilt constno

1388: bcompilecteimm getcte node

1389: if tail list getctebc getctebc

1390:

1391: define speciallexpos

1392: lambda frame offset

1393: case frame

1394: case offset else f

ANNEXE A SOURCES DU SYSTEME

1395: case offset else f

1396: case offset else f

1397: else f

1398:

1399: define bcompilereflex

1400: lambda node

1401: let loc getloc node

1402: frame car loc

1403: offset cdr loc

1404: spec speciallexpos frame if offset offset

1405: cond spec

1406: list spec

1407: offset

1408: if and frame offset

1409: list frame offset

1410: list bcompileno frame bcompileno offset

1411: else

1412: if frame

1413: list frame

1414: list bcompileno frame

1415:

1416: define bcompilerefglob

1417: lambda node lib

1418: let loc getloc node

1419: vardesc vectorref globv loc

1420: physno if lib getlibno vardesc getsrcno vardesc

1421: if physno

1422: list physno

1423: list bcompileno physno

1424:

1425: define bcompileref

1426: lambda node tail lib

1427: let result if getglob node

1428: bcompilerefglob node lib

1429: bcompilereflex node

1430: if tail list result result

1431:

1432: define bcompilesetlex

1433: lambda node

1434: let loc getloc node

1435: frame car loc

1436: offset cdr loc

1437: if offset

1438: if and frame offset

1439: list frame offset

1440: list bcompileno frame bcompileno offset

1441: if frame

1442: list frame

1443: list bcompileno frame

1444:

1445: define bcompilesetglob

1446: lambda node lib

1447: let loc getloc node

1448: vardesc vectorref globv loc

1449: physno if lib getlibno vardesc getsrcno vardesc

1450: if physno

1451: list physno

1452: list bcompileno physno

1453:

1454: define bcompileset

1455: lambda node tail lib

1456: let exp getexp node

1457: expbc bcompile exp f lib

1458: affbc if getglob node

1459: bcompilesetglob node lib

1460: bcompilesetlex node

1461: setbc list expbc affbc

1462: if tail list setbc setbc

1463:

1464: define bcompiledef

1465: lambda node tail lib

1466: let exp getexp node

1467: expbc bcompile exp f lib

1468: affbc bcompilesetglob node lib

1469: defbc list expbc affbc

1470: if tail list defbc defbc

1471:

1472: define bcompilepopn

1473: lambda n

1474: cond n

1475:

1476: n

1477: list n

1478: else

1479: list bcompileno n

1480:

1481: define bcompilebegin

1482: lambda node tail lib

1483: let loop lexp getlexp node nbprev

1484: if null cdr lexp

1485: list bcompilepopn nbprev

1486: bcompile car lexp tail lib

1487: list bcompile car lexp f lib

1488: loop cdr lexp nbprev

1489:

1490: define bcompilelabeldef

1491: lambda no

1492: list def no

1493:

1494: define bcompilelabelref

1495: lambda no

1496: list ref no

1497:

1498: define bcompileif

1499: lambda node tail lib

1500: let debutaltern makelabel

1501: finaltern if tail f makelabel

1502: testbc bcompile gettest node f lib

1503: cjumpbc list bcompilelabelref debutaltern

1504: conseqbc bcompile getconseq node tail lib

1505: ujumpbc if tail

1506:

1507: list bcompilelabelref finaltern

1508: debutalternbc bcompilelabeldef debutaltern

1509: alternbc bcompile getaltern node tail lib

1510: finalternbc if tail

1511:

1512: bcompilelabeldef finaltern

1513: list testbc cjumpbc conseqbc ujumpbc

1514: debutalternbc alternbc finalternbc

1515:

1516: define bcompilemakeframe

1517: lambda fdesc

1518: let nbreq car fdesc

1519: fac cdr fdesc

1520: framesize nbreq if fac

1521: cond framesize

1522:

ANNEXE A SOURCES DU SYSTEME

1523: and framesize not fac

1524:

1525: and framesize not fac

1526:

1527: and framesize fac

1528:

1529: fac

1530: if framesize

1531: list framesize

1532: list bcompileno framesize

1533: else

1534: if framesize

1535: list framesize

1536: list bcompileno framesize

1537:

1538: define bcompileclosure

1539: lambda node lib

1540: let fdesc getfdesc node

1541: makeframebc bcompilemakeframe fdesc

1542: bodybc bcompile getbody node t lib

1543: list makeframebc bodybc

1544:

1545: define bcompilelambda

1546: lambda node tail lib

1547: let closbc bcompileclosure node lib

1548: if tail

1549: list closbc

1550: let suite makelabel

1551: makeclosbc list bcompilelabelref suite

1552: suitebc bcompilelabeldef suite

1553: list makeclosbc closbc suitebc

1554:

1555: define bcompilecalcargs

1556: lambda larg lib

1557: let loop larg larg prevargsbc

1558: if null larg

1559: prevargsbc

1560: let arg car larg

1561: reste cdr larg

1562: calcargbc bcompile arg f lib

1563: loop reste list calcargbc prevargsbc

1564:

1565: define bcompilecallC

1566: lambda node tail lib

1567: let cprimno cdr getval getop node

1568: if cprimno applycprimno

1569: bcompilecallI node tail lib Le cas apply

1570: let larg getlarg node

1571: calcargsbc bcompilecalcargs larg lib

1572: applybc list cprimno

1573: callbc list calcargsbc applybc

1574: if tail

1575: list callbc

1576: list callbc

1577:

1578: define bcompilecallFi

1579: lambda node tail lib

1580: let op getop node

1581: larg getlarg node

1582: calcargsbc bcompilecalcargs larg lib

1583: fdesc getfdesc op

1584: makeframebc bcompilemakeframe fdesc

1585: body getbody op

1586: bodybc bcompile body tail lib

1587: if tail

1588: list calcargsbc makeframebc bodybc

1589: list calcargsbc makeframebc bodybc

1590:

1591: define bcompilecallI

1592: lambda node tail lib

1593: let op getop node

1594: if and refnode op getglob op

1595: let larg getlarg node

1596: calcargsbc bcompilecalcargs larg lib

1597: vardesc vectorref globv getloc op

1598: physno if lib getlibno vardesc getsrcno vardesc

1599: if physno

1600: if tail

1601: list calcargsbc physno

1602: list calcargsbc physno

1603: if tail

1604: list calcargsbc bcompileno physno

1605: list calcargsbc bcompileno physno

1606: let larg getlarg node

1607: allarg cons op larg

1608: allargbc bcompilecalcargs allarg lib

1609: if tail

1610: list allargbc

1611: list allargbc

1612:

1613: define bcompilecall

1614: lambda node tail lib

1615: let op getop node

1616: cond refnode op

1617: let val getval op

1618: if and val eq car val cprim

1619: bcompilecallC node tail lib

1620: bcompilecallI node tail lib

1621: lambdanode op

1622: bcompilecallFi node tail lib

1623: else

1624: bcompilecallI node tail lib

1625:

1626: define bcompile

1627: let actionv

1628: vector

1629: bcompilecte

1630: bcompileref

1631: bcompilelambda

1632: bcompileif

1633: bcompileset

1634: bcompilebegin

1635: bcompiledef

1636: bcompilecall

1637: lambda node tail lib

1638: vectorref actionv nodetype node node tail lib

1639:

1640: define bcompileprogram

1641: lambda

1642: map lambda ass setlabel cdr ass makelabel

1643: reqclosnodes

1644: let sourcebc map lambda node list bcompile node f f

1645: lnode

1646: finbc list

1647: libbc map lambda ass

1648: let node cdr ass

1649: list bcompilelabeldef getlabel node

1650: bcompileclosure node t

ANNEXE A SOURCES DU SYSTEME

1651: reqclosnodes

1652: applyhookbc list

1653: list sourcebc finbc libbc applyhookbc

1654:

1655: define flattenbytecode

1656: lambda hierarcode

1657: let loop h hierarcode rest

1658: if pair h

1659: loop car h loop cdr h rest

1660: if null h

1661: rest

1662: cons h rest

1663:

1664: define linkbytecode

1665: lambda flatrelocbc

1666: let loop bc flatrelocbc pos

1667: if not null bc

1668: let head car bc

1669: cond number head

1670: loop cdr bc pos

1671: eq head ref

1672: loop cddr bc pos

1673: else eq head def

1674: let labelno cadr bc

1675: vectorset labelv labelno pos

1676: loop cddr bc pos

1677: let loop bc flatrelocbc

1678: if null bc

1679:

1680: let head car bc

1681: cond number head

1682: cons head loop cdr bc

1683: eq head ref

1684: let labelno cadr bc

1685: pos vectorref labelv labelno

1686: append bcompileno pos loop cddr bc

1687: else eq head def

1688: loop cddr bc

1689:

1690:

1691:

1692:

1693: Codage de la valeur initiale des variables globales

1694:

1695: define globvarinitcodes f

1696:

1697: define codeinit

1698: lambda init

1699: cond not init

1700:

1701: eq car init cprim

1702: cdr init

1703: else eq car init clos

1704: let lambdanode cdr init

1705: labelno getlabel lambdanode

1706: vectorref labelv labelno

1707:

1708: define codeglobinits

1709: lambda

1710: let loop varno globcounter codes

1711: if varno

1712: codes

1713: let vardesc vectorref globv varno

1714: varinit getinit vardesc

1715: initcode codeinit varinit

1716: newcodes if getlibno vardesc

1717: getsrcno vardesc

1718: cons initcode codes

1719: cons initcode cons initcode codes

1720: loop varno newcodes

1721:

1722:

1723:

1724:

1725: Impression des resultats

1726:

1727: define bytestrings

1728: vector

1729:

1730:

1731:

1732:

1733:

1734:

1735:

1736:

1737:

1738:

1739:

1740:

1741:

1742:

1743:

1744:

1745:

1746:

1747:

1748:

1749:

1750:

1751:

1752:

1753:

1754:

1755:

1756: define writebytecode

1757: lambda bc port

1758: display int bytecodelen port

1759: let len length bc

1760: write len port

1761: if len

1762: begin

1763: display Warning bytecode too long

1764: newline

1765: display port

1766: newline port

1767: display unsigned char bytecode port

1768: let virgule

1769: let loop bc bc mod

1770: if not null bc

1771: begin

1772: display virgule port

1773: set virgule

1774: if mod

1775: begin

1776: newline port

1777: display port

1778: set mod

ANNEXE A SOURCES DU SYSTEME

1779: display vectorref bytestrings car bc port

1780: loop cdr bc mod

1781: display port

1782: newline port

1783:

1784: define writeconstdesc

1785: lambda cd port

1786: let cd map charinteger stringlist cd

1787: display int constdesclen port

1788: write length cd port

1789: display port

1790: newline port

1791: display unsigned char constdesc port

1792: let virgule

1793: let loop cd cd mod

1794: if not null cd

1795: begin

1796: display virgule port

1797: set virgule

1798: if mod

1799: begin

1800: newline port

1801: display port

1802: set mod

1803: display vectorref bytestrings car cd port

1804: loop cdr cd mod

1805: display port

1806: newline port

1807:

1808: define prettysignedint

1809: lambda int

1810: let sint numberstring int

1811: lpadding stringlength sint

1812: padding substring lpadding

1813: stringappend padding sint

1814:

1815: define writeglobinitcodes

1816: lambda globvarinitcodes port

1817: display int nbscmglobs port

1818: write length globvarinitcodes port

1819: display port

1820: newline port

1821: display int scmglobs port

1822: let virgule

1823: let loop gi globvarinitcodes mod

1824: if not null gi

1825: begin

1826: display virgule port

1827: set virgule

1828: if mod

1829: begin

1830: newline port

1831: display port

1832: set mod

1833: display prettysignedint car gi port

1834: loop cdr gi mod

1835: display port

1836: newline port

1837:

1838: define writeoutput

1839: lambda finalprogrambytecode

1840: constdescstring

1841: globvarinitcodes

1842: nameout

1843: let port openoutputfile nameout

1844: writebytecode finalprogrambytecode port newline port

1845: writeconstdesc constdescstring port newline port

1846: writeglobinitcodes globvarinitcodes port

1847: closeoutputport port

1848:

1849:

1850:

1851:

1852: Programme principal

1853:

1854: define bytecompile

1855: lambda namein nameout

1856: initglobvars

1857: let source readsource namein

1858: sourcesymbols findallsymbols source

1859: uniqpref finduniqprefix sourcesymbols

1860: set gensympref uniqpref

1861: set safenamememv gensym

1862: set safenamemakepromise gensym

1863: set safenamelistvector gensym

1864: set safenamelist gensym

1865: set safenameappend gensym

1866: set safenamecons gensym

1867: let source

1868: append

1869: list

1870: list define safenamememv memv

1871: list define safenamemakepromise makepromise

1872: list define safenamelistvector listvector

1873: list define safenamelist list

1874: list define safenameappend append

1875: list define safenamecons cons

1876: installconst

1877: source

1878: simple map transsub source

1879: set lnode map expnode simple

1880: let llglob map extractglobnames lnode

1881: lglob foldr symbolsetunion llglob

1882: loadlib

1883: set dirreq symbolsetintersection lglob libpublics

1884: grablib dirreq

1885: traverse

1886: findinits

1887: traverse

1888: assignphysno

1889: set programbytecode bcompileprogram

1890: set flatprogrambytecode flattenbytecode programbytecode

1891: set finalprogrambytecode linkbytecode flatprogrambytecode

1892: set constdescstring codeconst

1893: set globvarinitcodes codeglobinits

1894: writeoutput finalprogrambytecode constdescstring

1895: globvarinitcodes nameout

ANNEXE A SOURCES DU SYSTEME

A Exemple de compilation vers du co deo ctets

Supp osons que lon compile le p etit programme suivant

display Hello world

newline

Le chier pro duit par le compilateur vers du co deo ctets est le suivant p our plus de clarte

plusieurs lignes sont elidees

int bytecodelen

unsigned char bytecode

int constdesclen

unsigned char constdesc

int nbscmglobs

int scmglobs