OCaml internes: Exceptions
je suis curieux de savoir comment les exceptions sont traitées dans L'exécution OCaml pour les rendre si légères. Utilisent-ils setjmp/longjmp, ou font-ils retourner une valeur particulière dans chaque fonction, et de le propager?
il me semble que longjmp mettrait un peu de pression sur le système, mais seulement quand une exception est soulevée, tout en vérifiant pour chaque valeur de retour de fonction devrait vérifier pour chaque valeur après avoir appelé une fonction, ce qui me semble mettre beaucoup de vérifications et de sauts, et il semble qu'elle allait effectuer un pire.
En regardant comment OCaml interfaces avec C ( http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc142 ), et en regardant de rappel.h, il semble qu'une exception soit marquée en utilisant l'alignement mémoire des objets (#define Is_exception_result (v)) (((v) & 3) == 2) ). Cela semble indiquer que son implémentation n'utilise pas longjmp et vérifie chaque résultat de fonction après chaque appel de fonction. Est ce que c'est? Ou la fonction C essaie déjà d'attraper n'importe quelle exception, et puis la convertit à ce format?
Merci!
1 réponses
OCaml gestion des exceptions
Il n'utilise pas setjmp/longjmp
. Lorsqu'un try <expr> with <handle>
est évalué, un "piège" est placé sur la pile, qui contient des informations sur le gestionnaire. L'adresse du piège le plus haut est conservée dans un register1, et quand vous soulevez, il saute directement à ce piège, débitant plusieurs cadres de pile en une seule fois (c'est mieux que de vérifier chaque code de retour). Un piège aussi stocke l'adresse de la précédente piège, qui est restauré dans le registre à soulever temps.
1: ou mondiale, sur des architectures avec pas assez de registres
Vous pouvez voir par vous-même dans le code:
- compilation bytecode: lignes 635-641, deux
Kpushtrap/Kpoptrap
bytecode surroundtry..with
ed expression - compilation native: lignes 254-260, de nouveau instructions
Lpushtrap/Lpoptrap
autour de l'expression - exécution bytecode pour le bytecode
PUSHTRAP
(les lieux de la piège/gestionnaire),POPTRAP
(supprimer, sans erreur de cas) etRAISE
(saut à la trappe) - code natif emission sur le mips et amd64 (par exemple)
comparaison avec setjmp
Ocaml utilise une convention d'appel non standard avec peu ou pas de registres sauvegardés par callee, ce qui rend cette convention (et la tail-récursion) efficace. Je suppose (mais je ne suis pas un expert) que C'est la raison pour laquelle C longjmp/setjmp
n'est pas aussi efficace sur la plupart des architecture. Voir, par exemple,c'x86_64 setjmp mise en œuvre cela ressemble exactement au mécanisme de piégeage précédent plus callee-registers save.
C'est pris en compte dans le interface C / OCaml: l'habitude d'appeler une fonction Caml de code en C, caml_callback
, ne pas les attraper OCaml-terre d'exception; vous devez utiliser un spécifique caml_callback_exn
si vous le souhaitez, qui configure son gestionnaire de pièges et sauve/restaure les registres de callee-saved de la convention d'appel C. Voir, par exemple. le code amd64, ce qui sauve les registres puis sautez à cette étiquette pour configurer le piège d'exception.