Почему все регистры сохраняются во время обработки исключений .NET? - PullRequest
4 голосов
/ 18 декабря 2011

По крайней мере, согласно описанию реализации обработки исключений Mono , все регистры x86 сохраняются при возникновении исключения. Кроме указателя стека (ESP), указателей кадра (EBP), указателей команд (EIP) и регистра, который содержит объект исключения, почему также сохраняются другие регистры? Зачем сохранять весь контекст, когда в .NET нет механизма продолжения выполнения в точке сразу после броска?

UPDATE:

EMCA заявляет следующее в разделе 12.3.2.4 Обзор обработки исключений:

  • Объект исключения, описывающий исключение, автоматически создается CLI и помещается на стек оценки в качестве первого элемента при входе в фильтр или предложение catch.

  • Невозможно возобновить выполнение в месте исключения, кроме как с помощью обработчика фильтра.

Я не знаю, как «кроме как с обработчиком фильтра» может быть достигнуто в свете предыдущего утверждения. Кроме того, описание кода операции endfilter имеет только два результата: «продолжить поиск другого обработчика исключений» или выполнить обработчик (который будет выполнять другой блок кодов операций CIL.) В нем отсутствует опция «resume». Поэтому я интерпретирую это несоответствие в спецификации, чтобы в основном означать, что .NET не поддерживает продолжение выполнения в точке сразу после броска. Может быть, в какой-то момент это было рассмотрено, но никогда полностью не реализовано и не реализовано.

ОБНОВЛЕНИЕ 2:

Кто-то указал, что «возобновление» может просто произойти, если никакой обработчик фильтра не решит перехватить исключение. Однако в спецификации для throw указано: «команда throw бросает объект исключения в стек и очищает стек». Очистка стека сделает невозможным выполнение кода сразу после оператора throw, так как для этого кода может потребоваться что-то в стеке.

1 Ответ

3 голосов
/ 19 декабря 2011

Вы смотрите на детали реализации: они, как правило, не совпадают со спецификацией ECMA по многим возможным причинам (например, простота реализации, совместное использование кода, предоставление дополнительной семантики, прогнозирование на будущее, оптимизация и т. Д.).

В данном конкретном случае есть несколько соображений.

Mono выполняет обработку исключений на основе представления состояния процессора, называемого MonoContext: поскольку эта структура используется и в других местах, она содержит все соответствующие регистры, даже если некоторые из них могут не понадобиться в некоторых особых случаях. В частности, обработка исключений может быть инициирована также из исключения процессора, где все регистры должны быть восстановлены, поэтому все они собираются.

Кто-то уже заметил, что контекст используется и для отладчика.

Рассмотрим также случай с методом try / catch, в котором catch является простой локальной установкой var. Теперь расширенный распределитель регистров может поместить локальную переменную, которая используется как перед броском (обратите внимание, что бросок может быть неявным, как нулевая ссылка, так что обрабатывается путем исключения из процессора), так и после перехвата в регистре, подобном edx. Если вы не сохраните все регистры в точке выброса / исключения, вы испортили состояние программы, так как edx перезаписывается во время обработки исключений.

В качестве последнего комментария: вы обеспокоены тем, что сохранение нескольких лишних регистров тратит впустую циклы процессора? Если вы действительно посчитаете потраченные циклы, то они полностью в шуме относительно всего, что должно произойти во время обработки исключений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...