caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* OCaml bytecode documentation?
@ 2006-05-22 17:30 Geoffrey Alan Washburn
  2006-05-22 20:02 ` [Caml-list] " David MENTRE
  0 siblings, 1 reply; 6+ messages in thread
From: Geoffrey Alan Washburn @ 2006-05-22 17:30 UTC (permalink / raw)
  To: caml-list


	Where would I look for more information about the bytecode language 
used by current versions of OCaml?  Is it still based upon CAM?  Thanks.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] OCaml bytecode documentation?
  2006-05-22 17:30 OCaml bytecode documentation? Geoffrey Alan Washburn
@ 2006-05-22 20:02 ` David MENTRE
  2006-05-22 21:53   ` Geoffrey Alan Washburn
  0 siblings, 1 reply; 6+ messages in thread
From: David MENTRE @ 2006-05-22 20:02 UTC (permalink / raw)
  To: Geoffrey Alan Washburn; +Cc: caml-list

Geoffrey Alan Washburn <geoffw@cis.upenn.edu> writes:

> 	Where would I look for more information about the bytecode
> language used by current versions of OCaml?  Is it still based upon CAM?

Would this help?
 http://cristal.inria.fr/~lebotlan/docaml_html/english/english004.html

Best wishes,
d.
-- 
pub  1024D/A3AD7A2A 2004-10-03 David MENTRE <dmentre@linux-france.org>
 5996 CC46 4612 9CA4 3562  D7AC 6C67 9E96 A3AD 7A2A


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: OCaml bytecode documentation?
  2006-05-22 20:02 ` [Caml-list] " David MENTRE
@ 2006-05-22 21:53   ` Geoffrey Alan Washburn
  2006-05-23  5:49     ` [Caml-list] " Alan Schmitt
  0 siblings, 1 reply; 6+ messages in thread
From: Geoffrey Alan Washburn @ 2006-05-22 21:53 UTC (permalink / raw)
  To: caml-list; +Cc: caml-list

David MENTRE wrote:
> Geoffrey Alan Washburn <geoffw@cis.upenn.edu> writes:
> 
>> 	Where would I look for more information about the bytecode
>> language used by current versions of OCaml?  Is it still based upon CAM?
> 
> Would this help?
>  http://cristal.inria.fr/~lebotlan/docaml_html/english/english004.html

	Probably, though why isn't this part of the "official" documentation, 
or at least linked from, caml.inria.fr?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Re: OCaml bytecode documentation?
  2006-05-22 21:53   ` Geoffrey Alan Washburn
@ 2006-05-23  5:49     ` Alan Schmitt
  2006-05-23  7:02       ` [Caml-list] doc licence (was: OCaml bytecode documentation?) Florent Monnier
  2006-05-23  7:38       ` [Caml-list] Re: OCaml bytecode documentation? Francois Pottier
  0 siblings, 2 replies; 6+ messages in thread
From: Alan Schmitt @ 2006-05-23  5:49 UTC (permalink / raw)
  To: Geoffrey Alan Washburn; +Cc: David MENTRE, caml-list

[-- Attachment #1: Type: text/plain, Size: 894 bytes --]

On 22 mai 06, at 23:53, Geoffrey Alan Washburn wrote:

> David MENTRE wrote:
>> Geoffrey Alan Washburn <geoffw@cis.upenn.edu> writes:
>>> 	Where would I look for more information about the bytecode
>>> language used by current versions of OCaml?  Is it still based  
>>> upon CAM?
>> Would this help?
>>  http://cristal.inria.fr/~lebotlan/docaml_html/english/ 
>> english004.html
>
> 	Probably, though why isn't this part of the "official"  
> documentation, or at least linked from, caml.inria.fr?

Unfortunately neither Didier nor I have given time to this project  
for a long time. The best documentation is the ZINC technical report  
(http://gallium.inria.fr/~xleroy/publi/ZINC.pdf) along with the code  
(interp.c if I remember correctly).

Alan

-- 
Alan Schmitt <http://alan.petitepomme.net/>

The hacker: someone who figured things out and made something cool  
happen.
.O.
..O
OOO



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 186 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] doc licence (was: OCaml bytecode documentation?)
  2006-05-23  5:49     ` [Caml-list] " Alan Schmitt
@ 2006-05-23  7:02       ` Florent Monnier
  2006-05-23  7:38       ` [Caml-list] Re: OCaml bytecode documentation? Francois Pottier
  1 sibling, 0 replies; 6+ messages in thread
From: Florent Monnier @ 2006-05-23  7:02 UTC (permalink / raw)
  To: caml-list

> >>> 	Where would I look for more information about the bytecode
> >>> language used by current versions of OCaml?  Is it still based
> >>> upon CAM?
> >>
> >> Would this help?
> >>  http://cristal.inria.fr/~lebotlan/docaml_html/english/
> >> english004.html
> >
> > 	Probably, though why isn't this part of the "official"
> > documentation, or at least linked from, caml.inria.fr?
>
> Unfortunately neither Didier nor I have given time to this project
> for a long time. The best documentation is the ZINC technical report
> (http://gallium.inria.fr/~xleroy/publi/ZINC.pdf) along with the code
> (interp.c if I remember correctly).

There is a good news with the fact that the implementation doc is not part of 
the official doc: the implementation doc is available under GNU/FDL (GNU Free 
Documentation License), while the official doc is available in a restrictive 
way.

-- 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Re: OCaml bytecode documentation?
  2006-05-23  5:49     ` [Caml-list] " Alan Schmitt
  2006-05-23  7:02       ` [Caml-list] doc licence (was: OCaml bytecode documentation?) Florent Monnier
@ 2006-05-23  7:38       ` Francois Pottier
  1 sibling, 0 replies; 6+ messages in thread
From: Francois Pottier @ 2006-05-23  7:38 UTC (permalink / raw)
  To: Alan Schmitt; +Cc: Geoffrey Alan Washburn, caml-list, David MENTRE

[-- Attachment #1: Type: text/plain, Size: 520 bytes --]


Hello,

> >>Geoffrey Alan Washburn <geoffw@cis.upenn.edu> writes:
> >>>	Where would I look for more information about the bytecode
> >>>language used by current versions of OCaml?  Is it still based  
> >>>upon CAM?

Attached are some notes that I took on the OCaml bytecode language and
interpreter. Unfortunately, they are in French, for whatever reason. Also,
there is no guarantee that they are correct. They are from October 2003.

-- 
François Pottier
Francois.Pottier@inria.fr
http://cristal.inria.fr/~fpottier/

[-- Attachment #2: byterun --]
[-- Type: text/plain, Size: 28737 bytes --]

Quelques notes sur l'interpréteur de bytecode OCaml.

Fichiers alloc.c et alloc.h:
----------------------------
Diverses fonctions d'allocation mémoire.

Fichier array.c:
----------------
Fonctions de création et d'accès aux tableaux.

Fichiers backtrace.c et backtrace.h:
------------------------------------
Gestion des backtraces d'exceptions.

Les backtraces sont stockés dans un buffer global de taille fixe. Ils sont créés à la demande
(cf. RAISE). Ils sont constitutés simplement d'une liste d'adresses de retour. Lorsqu'on désire
les afficher, ils sont interprétés pour donner quelque chose de lisible. Cela demande de rouvrir
le fichier bytecode pour en extraire la section "DBUG", laquelle est disponible si le programme
a été compilé avec l'option -g.

Fichiers callback.h et callback.c:
----------------------------------
Fonctions permettant d'invoquer une clôture Caml depuis une fonction C.
Existent en deux variantes, selon que l'on veut que les exceptions soient propagées ou non.

Fichiers compact.h et compact.c:
--------------------------------
GC.

Fichier config.h:
-----------------
Règle un ensemble de paramètres liés à la gestion de la mémoire.

Fichiers custom.c et custom.h:
------------------------------
Allocation et gestion des blocs `custom', c'est-à-dire dotés de fonctions propres pour
la finalisation, la comparaison, le hashing, la sérialisation et désérialisation.

Fichiers debugger.c et debugger.h:
----------------------------------
Interface avec le debugger. Lorsque la fonction [debugger] est appelée, on tombe dans
un mode où on écoute les commandes envoyées par le debugger sur une socket, et on y
répond. On sort de ce mode et on reprend l'exécution lorsque le debugger dit 'GO'.

Fichiers dynlink.c et dynlink.h:
--------------------------------
Gestion des librairies partagées.

Fichier exec.h:
---------------
Décrit la structure des fichiers bytecode.

Fichier extern.c:
-----------------
La mécanique de sérialisation (output_value).

Fichiers fail.c et fail.h:
--------------------------
Fournit diverses fonctions liées aux exceptions. Une série de fonctions permettent de lever
des exceptions prédéfinies. Ces fonctions sont définies en termes de [raise_constant] et
[raise_with_arg], qui allouent un objet exception à partir de son nom (un pointeur vers un
bloc dans le tas) et d'un éventuel argument et appellent [mlraise]. Quant à [mlraise], il
stocke un pointeur vers l'objet exception dans une variable globale, [exn_bucket], et
effectue un [siglongjmp] à l'aide du [longjmp_buffer] [external_raise], qui doit avoir été
défini au préalable, sans quoi l'exception est considérée comme non rattrapée et l'exécution
cesse. Cette définition se situe dans le code d'initialisation de l'interprète (interp.c),
où on trouve un appel à [sigsetjmp].

Fichiers finalise.c et finalise.h:
----------------------------------
GC.

Fichiers fix_code.c et fix_code.h:
----------------------------------
Charge le bytecode en mémoire. En calcule un digest MD5, qui sert de signature lorsqu'on fait
du marshalling de clôtures. Corrige le code si le processeur est big endian (ce genre de détail
apparaît en d'autres endroits, dès qu'on lit des mots et non des octets). Si on souhaite utiliser
le threaded code, réécrit le code en remplaçant tous les opcodes par des pointeurs dans la table
de saut.

Fichier floats.c:
-----------------
La librairie standard sur les flottants.

Fichiers freelist.c et freelist.h:
----------------------------------
GC.

Fichiers gc_ctrl.c et gc_ctrl.h:
--------------------------------
GC.

Fichier gc.h:
-------------
Macros reliés au GC.

Fichiers globroots.c et globroots.h:
------------------------------------
GC (enregistrement des racines globales).

Fichier hash.c:
---------------
Implémente la fonction de hash primitive.

Fichiers instrtrace.c et instrtrace.h:
--------------------------------------
Permettent d'imprimer les instructions au fur et à mesure qu'elles sont exécutées.
Contient donc un désassembleur primaire (les adresses sont imprimées sous formes d'offsets bruts).
Ce mode est activé en passant l'option 't' à ocamlrun, à condition qu'il ait été compilé avec
l'option DEBUG.

Fichier instruct.h:
-------------------
Définit le jeu d'instructions, associant ainsi un entier à chaque opcode symbolique.

Fichiers int64_emul.h, int64_format.h, int64_native.h:
------------------------------------------------------
Émule l'arithmétique 64 bits et l'affichage des entiers 64 bits, pour les compilateurs C qui ne la supportent pas.
Pour ceux qui la supportent, définit des macros triviales.

Fichier intern.c:
-----------------
La mécanique de désérialisation (input_value).

Fichiers interp.c et interp.h:
------------------------------
Le coeur de l'interprète de bytecode.

Les registres de l'interprète sont les suivants: [pc] est un pointeur vers la prochaine
instruction à exécuter; [sp] est le pointeur de pile; [accu] l'accumulateur, un registre distingué
manipulé par certaines instructions; [env] un pointeur un bloc dans le tas (en fait une clôture)
contenant l'environnement courant; [trapsp] un pointeur vers le handler le plus récent dans la
pile; [extra_args] un registre dédié à la gestion des sous- et sur- applications de
fonctions. [accu] et [env] sont des racines potentielles pour le GC, mais ne lui sont pas
directement visibles; ils sont copiés sur la pile avant chaque appel au GC et restaurés
ensuite. [sp] est copié dans la variable globale [extern_sp] lors des appels au GC, aux primitives
C, etc. On utilise des "macros d'ordre supérieur": l'interprète définit les macros [Setup_for_gc]
et [Restore_after_gc], qui sont elles-mêmes appelées par la macro [Alloc_small] (memory.h), qui va
servir à chaque allocation de bloc.

L'interprète est apparemment conçu pour être réentrant: on a un compteur [callback_depth] qui
compte combien de fois il a été invoqué au-dessus de lui-même. Ce compteur est incrémenté lorsque
l'interprète démarre. Il est décrémenté lorsque l'interprète termine sur une exception non
rattrapée (instruction RAISE) ou termine normalement (instruction STOP).

Au démarrage, l'interprète effectue un [sigsetjmp] destiné à rattraper les exceptions lancées
depuis une primitive C (fail.c). Lorsqu'une telle exception est rattrapée, il restaure les racines
locales du GC, le pointeur de pile tel qu'il était avant l'appel à C, place l'exception dans
l'accumulateur, et exécute ensuite l'instruction RAISE, de façon à propager l'exception.

Il initialise ensuite les registres. [sp] est lu depuis [extern_sp], ce qui doit permettre de
reprendre la pile là où elle en était en cas d'appel réentrant. L'environnement initial est
vide. Ensuite, on attaque la boucle d'exécution.

Voici maintenant la description des instructions. Je ne discute pas ici précisément le codage
binaire des instructions, qui n'est pas très intéressant. En particulier, les sauts relatifs
utilisent des offsets dont l'origine est en général l'instruction dans laquelle ils se trouvent,
plus une constante. Je ne précise pas cela, ce qui revient à supposer que les sauts sont absolus.

Opérations de manipulation de la pile.

ACC n
  Place la valeur du n-ième mot de la pile dans l'accumulateur. Les éléments de la pile
  sont numérotés à partir de 0.
  Existe en version ACCn pour n entre 0 et 7 inclus.

PUSH
  Sauvegarde l'accumulateur sur la pile, dont la hauteur augmente donc de 1.

PUSHACC n
  Équivalent à la séquence PUSH; ACC n. À noter que PUSHACC0 est donc équivalent à PUSH.
  Existe en version PUSHACCn pour n entre 0 et 7 inclus.

POP n
  Détruit n mots au sommet de la pile, dont la hauteur diminue donc de n.

ASSIGN n
  Copie l'accumulateur dans le n-ième mot de la pile, sans changer la hauteur de celle-ci.
  L'accumulateur est ensuite effacé et reçoit un pointeur vers la valeur [unit].

Accès à l'environnement.

ENVACC n
  Place la valeur de la n-ième entrée de l'environnement dans l'accumulateur. Les entrées
  de l'environnement sont numérotées à partir de 0, mais l'entrée 0 est en général un
  pointeur de code, dans la mesure où l'environnement n'est autre que la clôture de la
  fonction en cours d'exécution.
  Existe en version ENVACCn pour n compris entre 1 et 4 inclus.

PUSHENVACC n
  Équivalent à la séquence PUSH; ENVACC n.
  Existe en version PUSHENVACCn pour n compris entre 1 et 4 inclus.

Applications de fonctions.

PUSH_RETADDR n
  Sauvegarde, dans l'ordre, sur la pile:
  + la valeur courante du registre [extra_args];
  + la valeur courante du registre [env];
  + une adresse de retour, calculée comme l'adresse de l'instruction suivante + n - 1;
    pour pouvoir implanter correctement les appels terminaux, l'adresse de retour n'est
    donc pas forcément l'adresse de l'instruction suivante.

APPLY n
  Exige qu'un pointeur vers une clôture soit présent dans l'accumulateur.
  Règle [extra_args] à n - 1, de sorte que celui-ci devient nul
  dans le cas courant de l'application unaire (n=1).
  Met à jour [pc] et [env] pour l'exécution de la clôture.
  Si le pointeur de pile a atteint la zone seuil, exige une extension de la pile (stacks.c).
  Si un signal a eu lieu, traite celui-ci (signals.c).

APPLYn
  Attention, cet opcode n'est pas équivalent à APPLY n! On peut en résumer l'effet comme suit:
  + Retire n mots de la pile, qui représentent les arguments de la fonction;
  + Simule PUSH_RETADDR 1 (l'adresse de retour est donc l'instruction suivante);
  + Replace les n arguments sur la pile;
  + Simule APPLY n.
  Existe pour n entre 1 et 3 inclus.

APPTERM n s
  Exige s >= n.
  + Détruit le contenu de la pile entre les positions n (inclue) et n+s (exclue), ce qui
    correspond au scénario où on se prépare à effectuer un appel terminal, donc on jette
    la frame courante, de taille s, sauf les n arguments de la fonction à laquelle on
    transfère le contrôle;
  + Simule APPLY n, à cette différence près que [extra_args] ne *reçoit* pas la valeur
    n - 1, mais *est incrémenté* de n - 1, ce qui est important, puisque, contrairement
    au cas de l'application normale, [extra_args] n'est pas sauvegardé.
  Existe en version APPTERMn s pour n entre 1 et 3 inclus.

RETURN n
  + Détruit les n mots situés au sommet de la pile.
  + Si [extra_args] est nul, le sommet de la pile doit alors être constitué d'une frame de retour
    (cf. PUSH_RETADDR). L'instruction rétablit alors [pc], [env], et [extra_args], et détruit cette
    frame.
  + Sinon, le sommet de la pile doit être constitué d'arguments supplémentaires, et l'accumulateur
    (qui par convention contient le résultat de l'appel précédent) doit contenir une clôture. On
    décrémente alors [extra_args], et on met à jour [pc] et [env] pour exécuter cette clôture, ce
    qui correspond à un appel terminal.

RESTART
  Si l'environnement courant contient 1+n entrées (l'entrée numéro 0 étant toujours le pointeur
  de code, ignoré), alors les n-1 dernières entrées sont copiées sur la pile (l'entrée numéro 2
  devenant donc le nouveau sommet de pile), et l'entrée numéro 1 est écrite dans [env].

GRAB n
  Cette instruction doit être précédée d'un RESTART.
  + Si [extra_args] est supérieur ou égal à n, il est décrémenté de n.
  + Sinon, on alloue une clôture, dont les composantes sont les suivantes:
    * Le pointeur de code est le RESTART précédent.
    * L'entrée numéro 1 est la valeur courante de l'environnement.
    * Les entrées suivantes sont les [extra_args + 1] mots situés au sommet de la pile, qui sont dépilés.
    Cette clôture est placée dans l'accumulateur.
    Ensuite, on remet [extra_args] à zéro, et on simule RETURN.

CLOSURE n k
  Alloue et place dans l'accumulateur un pointeur vers une clôture dont les composantes sont les suivantes:
  + Le pointeur de code est situé à l'offset k;
  + L'environnement est constitué des n mots obtenus en concaténant la valeur initiale de l'accumulateur et
    les n-1 mots au sommet de la pile, qui sont dépilés.

CLOSUREREC f n k_0 k_1 .. k_f
  Exige f >= 1.
  Alloue une clôture dont les composantes sont les suivantes:
  + D'abord, un pointeur de code, situé à l'offset k_0;
  + Ensuite, pour chaque indice i entre 1 inclus et f exclus,
    * Un header de bloc portant le tag "infixe", de façon à ce qu'il soit permis (du point de vue du GC)
      de créer un pointeur vers cette position du bloc.
    * Un pointeur de code, situé à l'offset k_i;
  + Enfin, comme dans le cas CLOSURE, les n mots obtenus en concaténant la valeur initiale de l'accumulateur et
    les n-1 mots au sommet de la pile, qui sont dépilés.
  À l'issue de l'instruction, on trouve sur la pile les [f] clôtures partagées ainsi créées, celle située
  au sommet de la pile étant celle d'indice [f].

OFFSETCLOSURE n
  Charge dans l'accumulateur *l'adresse* de la n-ième entrée de l'environnement.
  Cela est utile dans le cas où on a créé des fonctions mutuellement récursives à l'aide de CLOSUREREC:
  lorsqu'on est en train d'exécuter une de ces fonctions, l'environnement contient donc un pointeur
  (éventuellement infixe) vers la clôture partagée, et l'instruction OFFSETCLOSURE permet donc de
  charger dans l'accumulateur un autre pointeur (lui aussi éventuellement infixe) vers cette même
  clôture. Autrement dit, si f et g sont deux fonctions mutuellement récursives, l'accès à f depuis
  g (ou vice-versa) se fait par OFFSETCLOSURE.
  Existe en version OFFSETCLOSUREn pour n=-2,0,2.

PUSHOFFSETCLOSURE n
  Équivalent à la séquence PUSH; OFFSETCLOSURE n.
  Existe en version PUSHOFFSETCLOSUREn pour n=-2,0,2.

Accès aux variables globales.

GETGLOBAL n
  Charge dans l'accumulateur le contenu de la variable globale numéro n.

PUSHGETGLOBAL n
  Équivalent à la séquence PUSH; GETGLOBAL n.

GETGLOBALFIELD n k
  Charge dans l'accumulateur le contenu du k-ième champ de la variable globale numéro n.

PUSHGETGLOBALFIELD n k
  Équivalent à la séquence PUSH; GETGLOBALFIELD n k.

SETGLOBAL n
  Copie l'accumulateur dans la variable globale numéro n.
  L'accumulateur reçoit ensuite la valeur [unit].

Allocation de blocs.

ATOM n
  L'accumulateur reçoit un pointeur vers l'atome numéro n (lequel est pré-alloué).
  Existe en version ATOMn pour n=0.

PUSHATOM n
  Équivalent à la séquence PUSH; ATOM n.
  Existe en version PUSHATOMn pour n=0.

MAKEBLOCK s t
  Alloue un bloc mémoire de taille s et d'étiquette t.
  Le premier champ reçoit la valeur courante de l'accumulateur, les s-1 autres champs sont pris sur la pile.
  L'adresse du bloc est placée dans l'accumulateur.
  Existe en version MAKEBLOCKs t pour s entre 1 et 3 inclus.

MAKEFLOATBLOCK s
  Alloue un bloc mémoire de taille appropriée pour recevoir s flottants et d'étiquette [Double_array_tag].
  Le premier champ reçoit la valeur courante de l'accumulateur, les s-1 autres champs sont pris sur la pile.
  (L'accumulateur, ainsi que chaque case de la pile, est capable de contenir un flottant.)
  L'adresse du bloc est placée dans l'accumulateur.

Accès aux composantes des blocs.

GETFIELD n
  Place dans l'accumulateur la valeur du n-ième champ de l'objet vers lequel pointe l'accumulateur.
  Existe en version GETFIELDn pour n entre 0 et 3 inclus.

GETFLOATFIELD n
  Place dans l'accumulateur la valeur *boxée* du n-ième champ de l'objet vers lequel pointe l'accumulateur.

SETFIELD n
  Dépile un mot, et le copie dans le n-ième champ de l'objet vers lequel pointe l'accumulateur.
  L'accumulateur reçoit la valeur [unit].
  Existe en version SETFIELDn pour n entre 0 et 3 inclus.

SETFLOATFIELD n
  Dépile l'adresse d'un flottant *boxé*, et en copie le contenu dans le n-ième champ
  de l'objet vers lequel pointe l'accumulateur.
  L'accumulateur reçoit la valeur [unit].

Opérations sur les tableaux.

VECTLENGTH
  Place dans l'accumulateur la longueur du tableau (en nombre d'éléments, que celui-ci soit un tableau
  de flottants ou non) situé dans l'accumulateur.

GETVECTITEM
  Accède au i-ème élément du tableau situé dans l'accumulateur, où i est le premier mot sur la pile (qui est dépilé).
  Le résultat est placé dans l'accumulateur.

SETVECTITEM
  Écrit la valeur v dans le i-ème élément du tableau situé dans l'accumulateur, où i est le premier mot sur la pile
  et v le second (qui sont dépilés). L'accumulateur est inchangé.

Opérations sur les chaînes de caractères.

GETSTRINGCHAR
  Similaire à GETVECTITEM, mais pour les tableaux de caractères.

SETSTRINGCHAR
  Similaire à SETVECTITEM, mais pour les tableaux de caractères.
  L'accumulateur reçoit la valeur [unit].

Branchements.

BRANCH k
  Branchement inconditionnel à l'offset k.

BRANCHIF k
  Branchement si l'accumulateur ne contient pas le booléen false.

BRANCHIFNOT k
  Branchement si l'accumulateur contient le booléen false.

SWITCH m n j_1 .. j_m k_1 .. k_n
  (m et n sont codés comme deux entiers de 16 bits.)
  + Si l'accumulateur contient un entier i, effectue un saut à l'offset j_i.
  + Si l'accumulateur contient un pointeur vers un bloc d'étiquette i, effectue un saut à l'offset k_i.

BOOLNOT
  Remplace l'accumulateur par sa négation.

Exceptions.

PUSHTRAP k
  Pousse sur la pile une frame contenant, du sommet vers le fond:
  + L'adresse du handler, situé à l'offset k;
  + La valeur courante de [trapsp], de sorte que les frames de handlers vont former une liste chaînée dans la pile;
  + La valeur courante de [env], de sorte qu'on stocke effectivement une clôture sur la pile, à savoir la
    continuation exceptionnelle;
  + La valeur courante de [extra_args];
  Pour finir, [trapsp] prend la valeur courante de [sp], c'est-à-dire qu'il vient pointer vers cette nouvelle frame.

POPTRAP
  Exige qu'une frame de handler soit située au sommet de la pile. On rétablit alors l'ancienne valeur de [trapsp]
  et on supprime la frame. Cela correspond à la sortie normale d'un handler. Une petite subtilité est qu'il faut
  traiter les éventuels signaux en attente avant de sortir, sinon on risque de ne pas lever une exception au bon
  endroit. (Cela dit, dans la mesure où ces signaux auraient pu arriver plus tard, puisqu'ils sont asynchrones,
  je ne suis pas sûr qu'on violerait la sémantique en ne faisant pas cela.)

RAISE
  Si les backtraces sont activées, construit une backtrace pour cette exception en parcourant la pile de son sommet
  jusqu'à la première trap frame et en y identifiant toutes les adresses de retour de fonctions. (Les tail calls
  sont donc invisibles!) Ce mécanisme est rusé, car cela signifie que les backtraces ne coûtent rien tant qu'aucune
  exception n'est lancée, d'une part, et d'autre part que lorsqu'une exception est lancée, on ne paye d'abord que
  pour remonter jusqu'au premier handler; on ne construit pas tout de suite un backtrace depuis le début du monde,
  ce qui serait (difficile et) inutile si l'exception est rattrapée.

  Ensuite:
  + Si la pile contient une trap frame (donnée par [trapsp]), alors on l'utilise pour restaurer [pc], [trapsp],
    [env] et [extra_args], et on dépile tout jusqu'à (et y compris) cette frame.
  + Sinon, l'exception est considérée comme non rattrapée, et cette instance de l'interprète termine en renvoyant
    l'exception comme résultat.

Signaux.

CHECK_SIGNALS
  Traite les signaux en attente. Implicitement exécuté à chaque appel de fonction.

Appel de fonctions C.

C_CALLN n
  Pousse [accu] sur la pile, dont les n premiers mots forment alors les n arguments de la primitive C.
  Sauvegarde [pc] et [sp] dans des variables globales, et [env] sur la pile.
  Appelle la primitive C en lui fournissant le segment de pile où sont stockés ses n paramètres, et place
  le résultat dans l'accumulateur.
  Restaure ensuite [sp] et [env], et dépile les n paramètres.
  La primitive C peut également lancer une exception à l'aide de [mlraise], auquel cas la valeur sauvegardée de [pc]
  participera à la construction du backtrace. Elle semble par ailleurs inutilisée.

C_CALL1 à C_CALL5
  Versions spécialisées de C_CALLN pour N de 1 à 5. Le protocole d'appel de la fonction C n'est pas le même:
  lorsque N est connu statiquement, on lui passe directement N arguments, tandis que dans C_CALLN, on passe
  un pointeur vers un tableau de N arguments (un segment de pile, en fait), ainsi que N lui-même.

Constantes entières.

CONSTINT n
  Place la valeur entière n dans l'accumulateur.
  Existe en version CONSTn pour n de 0 à 3.

PUSHCONSTINT n
  Équivalent à la séquence PUSH; CONSTINT n.
  Existe en version PUSHCONSTn pour n de 0 à 3.

Arithmétique entière.

NEGINT
  Remplace l'accumulateur par sa négation entière.

ADDINT
SUBINT
MULINT
  Dépile un entier et l'ajoute/le soustrait/le multiplie à l'accumulateur.

DIVINT
MODINT
  Dépile un entier et divise/module l'accumulateur par cet entier.
  Lance une exception si le diviseur est nul.

ANDINT
ORINT
XORINT
LSLINT
LSRINT
ASRINT
  Dépile un entier et le combine à l'accumulateur par l'opération logique appropriée.

EQ
NEQ
LTINT
LEINT
GTINT
GEINT
ULTINT
UGEINT
  Dépile un entier et le compare à l'accumulateur par l'opération logique appropriée.
  Le résultat est placé dans l'accumulateur.

BEQ n k
BNEQ n k
BLTINT n k
BLEINT n k
BGTINT n k
BGEINT n k
BULTINT n k
BUGEINT n k
  B<op> k est équivalent à la séquence PUSH; CONSTINT n; <op>; BRANCHIF k.
  (Ce n'est pas forcément intuitif.)

OFFSETINT n
  Incrémente l'accumulateur de n.

OFFSETREF n
  Incrémente le premier champ de l'objet situé dans l'accumulateur de n.
  L'accumulateur reçoit la valeur [unit].

ISINT
  Place dans l'accumulateur un booléen indiquant si la valeur initiale de l'accumulateur est un entier ou un pointeur.

Opérations orientées objet.

GETMETHOD
  Suppose un objet situé dans le premier mot de la pile (il n'est pas dépilé), et un label de
  méthode situé dans l'accumulateur. L'accumulateur est remplacé par la clôture associée à cette
  méthode pour cet objet. Celle-ci est obtenue par trois indirections (la première extrait du premier
  champ de l'objet l'adresse de la table de dispatch, et les deux suivantes se font à travers la table).

Debugging et contrôle de la machine.

STOP
  Provoque l'arrêt normal de l'interprète. La valeur courante de l'accumulateur en constitue le résultat.

EVENT
  Décrémente le compteur d'événements, et provoque un appel au debugger si celui-ci tombe à zéro.
  Exécute ensuite l'instruction masquée par EVENT. (Lorsque le debugger est utilisé, l'interprète
  maintient deux exemplaires du code, l'original dans [saved_code], et une copie potentiellement
  patchée par le debugger pour exécution.)

BREAK
  Appelle le debugger, puis exécute l'instruction masquée par BREAK.

Fichier intext.h:
-----------------
Header commun aux fichiers extern.c et intern.c.

Fichier ints.c:
---------------
La librairie standard sur les entiers (affichage, opérations sur les entiers 32 et 64 bits).

Fichiers io.c et io.h:
----------------------
Implémente le type [channel] de la librairie standard.

Fichier lexing.c:
-----------------
Interprète pour les lexers engendrés par ocamllex.

Fichiers macintosh.c et macintosh.h:
------------------------------------
Implémentations (ou non-implémentations) de certaines routines sous MacOS.

Fichier main.c:
---------------
La fonction main, qui appelle caml_main.

Fichiers major_gc.c et major_gc.h:
----------------------------------
GC.

Fichiers md5.c et md5.h:
------------------------
Code domaine public pour calculer des digests md5.

Fichiers memory.c et memory.h:
------------------------------
Macros et fonctions d'allocation.

Fichier meta.c:
---------------
Fonctions magiques pour le toplevel.

Fichiers minor_gc.c et minor_gc.h:
----------------------------------
GC.

Fichiers misc.c et misc.h:
--------------------------
Diverses routines de rapport d'erreurs, ainsi que du code pour gérer des
tables extensibles.

Fichier mlvalues.h:
-------------------
Un tas de macros permettant de manipuler des valeurs Caml depuis C.

Fichier obj.c:
--------------
Implémentation de certaines fonctions des modules [Obj] et [Lazy].

Fichier osdeps.h:
-----------------
Déclare une série de fonctions OS dépendantes (parsing de chemins, librairies partagées, accès aux répertoires,
accès au nom de l'exécutable courant, etc.)

Fichier parsing.c:
------------------
Interprète pour les parsers engendrés par ocamlyacc.

Fichier prims.h:
----------------
Déclare la table des primitives et la façon d'y accéder.

Fichiers printexc.c et printexc.h:
----------------------------------
Affichage des exceptions non rattrapées, des backtraces, appel des fonctions enregistrées via [at_exit].

Fichier reverse.h:
------------------
Gestion de l'endianness.

Fichiers roots.c et roots.h:
----------------------------
GC.

Fichiers signals.c et signals.h:
--------------------------------
Gère les signaux. Une liste de clôtures est située dans la variable globale [signal_handlers].
On extrait celle correspondant au numéro du signal, et on l'exécute (callback.c), ce qui
déclenche un appel réentrant à l'interprète. Si l'exécution produit une exception, elle est
propagée (manuellement).

Contient également les fonctions [enter_blocking_section] et [leave_blocking_section]. Le premier
exécute tous les signaux en attente, puis active le drapeau [async_signal_mode].  Le second efface
ce même drapeau. Ce drapeau est utilisé par le gestionnaire de signaux [handle_signal]: si le
drapeau est activé, un signal est exécuté dès sa réception, mais sinon, il est mis en attente.
L'exécution d'un gestionnaire de signaux est toujours située dans une section bloquante, de
sorte qu'un signal ne peut interrompre la gestion d'un signal précédent.

Fichier stacks.c et stacks.h:
-----------------------------
Code de gestion de la pile. Celle-ci est initialement allouée par un appel à malloc.

La pile croît vers le bas. La partie inférieure de la pile (par défaut, les 256 positions inférieures)
forment le `seuil' de la pile. Pour gagner du temps, la plupart des instructions de la machine
virtuelle font croître la pile sans se prémunir contre les overflows; c'est seulement une fois
de temps en temps (à chaque appel de fonction, en fait) qu'on teste si le pointeur de pile se
trouve dans la zone seuil, et si oui, on demande une extension de la taille de la pile. Il ne
faut donc pas engendrer de code contenant plus de 256 instructions PUSH au sein d'une même
fonction...

Lorsqu'une extension de la pile est demandée, on teste si celle-ci dépasserait alors une certaine
valeur limite, et si oui, la requête est refusée, ce qui évite d'allouer gloutonnement toute la
mémoire disponible sur la machine. Si la requête est acceptée, alors la taille de la pile est
doublée: un nouveau bloc est allouée, et l'ancienne pile recopiée dedans. Tous les pointeurs
vers la pile sont réécrits, ce qui inclut certains registres globaux ainsi que toute la chaîne
des handlers d'exceptions.

Fichiers startup.c et startup.h:
--------------------------------
Alloue et initialise la table globale des 256 atomes (constructeurs de données non paramétrés).
Initialise le GC et la pile.

Analyse la ligne de commande, la variable $CAMLRUNPARAM. Détermine où trouver le bytecode: soit
dans un fichier dont le nom est spécifié sur la ligne de commande, soit dans l'exécutable courant
lui-même.

Ouvre le fichier de bytecode et en extrait le trailer, dont la structure, décrite dans [exec.h],
est la suivante: un entier non signé de 32 bits [num_sections], et un magic number dépendant de
la release. Juste avant le trailer, vient la table des matières (TOC), constituée de 8 octets
par section, à savoir un nom (de 4 caractères) et une longueur en octets (sur 32 bits). Le reste
du fichier est constitué des sections indiquées dans la table, dans l'ordre où elles apparaissent
dans la table.

Charge le code, situé dans la section "CODE" du fichier.

Charge le chemin des librairies partagées, situé dans la section "DLPT", ainsi que la liste des
librairies partagées, située dans la section "DLLS". Charge la liste des primitives, située dans
la section "PRIM". Utilise ces trois informations pour charger toutes les primitives requises.

Charge les variables globales préinitialisées, situées dans la section "DATA". Celles-ci sont
dans un format lisible par [input_value].

Pour terminer, lance l'exécution de l'interprète, et affiche le résultat si celui-ci est une
exception non rattrapée.

Fichier str.c:
--------------
La librairie standard sur les strings.

Fichier sys.c et sys.h:
-----------------------
Implémentation du module [Sys] de la librairie standard.

Fichier terminfo.c:
-------------------
Implémente apparemment un module de librairie (quoique je ne vois pas où ces fonctions sont accessibles en Caml).

Fichier unix.c:
---------------
Implémente osdeps.h pour Unix.

Fichiers weak.c et weak.h:
--------------------------
GC.

Fichier win32.c:
---------------
Implémente osdeps.h pour Windows.


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2006-05-23  7:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-05-22 17:30 OCaml bytecode documentation? Geoffrey Alan Washburn
2006-05-22 20:02 ` [Caml-list] " David MENTRE
2006-05-22 21:53   ` Geoffrey Alan Washburn
2006-05-23  5:49     ` [Caml-list] " Alan Schmitt
2006-05-23  7:02       ` [Caml-list] doc licence (was: OCaml bytecode documentation?) Florent Monnier
2006-05-23  7:38       ` [Caml-list] Re: OCaml bytecode documentation? Francois Pottier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).