Внутренние компоненты OCaml: исключения - PullRequest
21 голосов
/ 19 декабря 2011

Мне любопытно узнать, как обрабатываются исключения во время выполнения OCaml, чтобы сделать их такими легкими.Используют ли они setjmp / longjmp или они возвращают специальное значение в каждой функции и распространяют его?

Мне кажется, что longjmp будет немного напрягать систему, но только при возникновении исключения,при проверке для каждой функции возвращаемое значение должно было бы проверять каждое значение после вызова функции, что, как мне кажется, поставило бы много проверок и переходов, и, похоже, оно будет работать хуже всего.

При просмотрекак OCaml взаимодействует с C (http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc142) и, глядя на callback.h, кажется, что исключение помечается с помощью выравнивания объектов в памяти (#define Is_exception_result (v) (((v) & 3) == 2)).Кажется, это указывает на то, что его реализация не использует longjmp и проверяет каждый результат функции после каждого вызова функции.Это оно?Или функция C уже пытается перехватить любое исключение, а затем преобразовать его в этот формат?

Спасибо!

1 Ответ

42 голосов
/ 20 декабря 2011

Обработка исключений OCaml

Не используется setjmp/longjmp.Когда try <expr> with <handle> оценивается, в стек помещается «ловушка», которая содержит информацию об обработчике.Адрес самой верхней ловушки хранится в регистре¹, и когда вы повышаете, он сразу переходит к этой ловушке, разматывая несколько кадров стека за один раз (это лучше, чем проверка каждого кода возврата).Ловушка также хранит адрес предыдущей ловушки, которая восстанавливается в регистре во время вызова.

¹: или глобальная, для архитектур с недостаточным количеством регистров

Вы можете убедиться самив коде:

Сравнение с setjmp

В Ocaml используется нестандартное соглашение о вызовах с небольшим количеством регистров или без них, что делает этот метод (и хвостовую рекурсию) эффективным.Я полагаю (но я не эксперт), поэтому C longjmp/setjmp не так эффективна на большинстве архитектур.См., Например, эту реализацию x86_64 setjmp , которая выглядит точно так же, как предыдущий механизм захвата плюс сохранение регистров вызываемого абонента.

Это учитывается в интерфейсе C / OCaml : обычный способ вызова функции Caml из кода C, caml_callback, не перехватывает исключения OCaml-land;Вы должны использовать определенный caml_callback_exn, если хотите, который устанавливает его обработчик ловушек , а сохраняет / восстанавливает сохраненные вызываемыми регистры соглашения о вызовах C.См. Например код amd64 , который сохраняет регистры, затем перейдите к этой метке , чтобы настроить ловушку исключения.

...