Опубликован: 28.06.2006 | Уровень: специалист | Доступ: платный | ВУЗ: Московский государственный технический университет им. Н.Э. Баумана
Лекция 7:

Язык CIL: обработка исключений. Синтаксис ILASM

< Лекция 6 || Лекция 7: 123456 || Лекция 8 >
Аннотация: Механизмы поддержки обработки исключений в .NET, семантика обработки исключений. Основные элементы лексики и синтаксиса ассемблера ILASM.

Существует два основных способа перехвата ошибок, возникающих в процессе работы программы:

  • Обработка кодов возврата.

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

    Этот способ хорошо работает, если глубина стека вызовов функций в программе относительно невелика. В противном случае код программы из-за постоянных проверок становится громоздким и трудночитаемым.

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

    Этот способ заключается в том, что в случае возникновения ошибки генерируется так называемая исключительная ситуация (исключение), которая описывается некоторым объектом. Генерация исключения приводит к передаче управления на фрагмент кода программы, называемый обработчиком исключения. Преимуществом такого подхода является то, что перехват ошибок локализован в отдельной части программы, а не распределен по всему коду, как в случае с обработкой кодов возврата.

Основная трудность для понимания деталей реализации обработки исключений в CLI заключается в том, что обработка исключений частично закодирована в телах методов (в виде специальных инструкций), а частично - в заголовках методов. Скорее всего, такая смешанная схема была выбрана разработчиками CLI для обеспечения компактности сборок. Поэтому мы в данном разделе сначала рассмотрим ту часть информации об обработке исключений, которая расположена в заголовках методов, затем перейдем к инструкциям CIL и, в конце концов, свяжем все воедино, приведя семантику обработки исключений виртуальной системой выполнения.

Предложения обработки исключений в заголовках методов

Для дальнейшего изложения нам понадобится ввести понятия области в коде метода и координат области.

Будем называть областью непрерывную последовательность инструкций в коде метода. При этом область будет определяться своими координатами, а именно парой чисел ( offset, length ), где offset - это смещение первой инструкции области относительно начала тела метода, а length - длина области. Как смещение, так и длину будем измерять в байтах.

Заголовок каждого метода содержит специальный массив, элементы которого называются предложениями обработки исключений (exception handling clause).

Каждое предложение обработки исключений представляет собой структуру, состоящую из нескольких полей. В этих полях записаны координаты двух или трех областей, а именно: в любом предложении присутствуют координаты защищенной области (protected block) и области обработчика (exception handler), а в некоторых предложениях дополнительно описана область фильтра (filter block).

Если говорить в терминах языка C#, то защищенная область - это try-блок, а область обработчика - это либо catch-блок, либо finally-блок. Аналог для области фильтра в языке C# отсутствует, но зато он есть в Visual Basic .NET и в Visual C++ with Managed Extensions. Область фильтра содержит код, принимающий решение о том, может ли данное исключение быть обработано обработчиком. Естественно, такое представление о назначении областей в предложении обработки исключений несколько примитивно и понадобится нам лишь на начальном этапе.

Давайте рассмотрим два возможных формата, в которых кодируется массив предложений обработки исключений. В каждом из двух форматов содержатся одни и те же поля, и различаются они только размерами полей. Первый формат называется коротким форматом (см. таблицу 3.43) и используется тогда, когда смещения областей не превышают 65535 байт, а длины областей не превышают 255 байт. Во втором, длинном формате (см. таблицу 3.44) допускаются любые смещения и длины. Строго говоря, не любые, а укладывающиеся в 32 бита. Но на практике этого более чем достаточно.

Таблица 3.43. Поля предложения обработки исключений в случае короткого формата
Смещение Размер Поле Описание
0 2 Flags Флаги
2 2 TryOffset Координаты защищенной области
4 1 TryLength
5 2 HandlerOffset Координаты области обработчика
7 1 HandlerLengh
8 4 ClassToken Токен метаданных
8 4 FilterOffset Смещение области фильтра

Таблица 3.44. Поля предложения обработки исключений в случае длинного формата
Смещение Размер Поле Описание
0 4 Flags Флаги
4 4 TryOffset Координаты защищенной области
8 4 TryLength
12 4 HandlerOffset Координаты области обработчика
16 4 HandlerLengh
20 4 ClassToken Токен метаданных
20 4 FilterOffset Смещение области фильтра

Итак, координаты защищенной области задаются парой ( TryOffset, TryLength ), а координаты области обработчика - парой ( HandlerOffset, HandlerLength ). Для области фильтра указывается только ее смещение, потому что подразумевается, что она непосредственно предшествует области обработчика (длину области фильтра можно вычислить: она равна HandlerOffset - FilterOffset ).

Обратите внимание, что смещения полей ClassToken и FilterOffset совпадают. Это означает, что фактически они представляют собой одно поле. Просто иногда оно интерпретируется как токен метаданных, а иногда - как смещение области фильтра.

Поле Flags, возможные значения которого перечислены в таблице 3.45, задает тип обработчика.

Таблица 3.45. Допустимые значения поля Flags предложения обработки исключений
Значение Описание
0 Обработчик исключений с фильтрацией по типу
1 Обработчик исключений с пользовательской фильтрацией
2 Обработчик finally
4 Обработчик fault

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

  1. Обработчик с фильтрацией по типу.

    Получает управление, если тип исключения совместим по присваиванию с типом, указанным в поле ClassToken предложения обработки исключений.

  2. Обработчик с пользовательской фильтрацией.

    Решение о том, получит или не получит управление обработчик, принимает код, содержащийся в области фильтра.

  3. Обработчик finally.

    Вызывается при выходе из защищенной области, независимо от того, было или не было сгенерировано исключение.

  4. Обработчик fault.

    Вызывается, если внутри защищенной области было сгенерировано любое исключение.

Первые два типа обработчиков мы будем относить к категории обработчиков с фильтрацией, а последние два - к категории обработчиков без фильтрации.

< Лекция 6 || Лекция 7: 123456 || Лекция 8 >
Анастасия Булинкова
Анастасия Булинкова
Рабочим названием платформы .NET было
Bogdan Drumov
Bogdan Drumov
Молдова, Республика
Azamat Nurmanbetov
Azamat Nurmanbetov
Киргизия, Bishkek