Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 79 стр.

UptoLike

4.2.3. Присвоение родительских блоков узлам графа
На третьем этапе узлы, соответствующие инструкциям, получают ро-
дителей. Тем самым завершается построение дерева блоков.
Можно заметить, что все блоки графа, включая блок тела метода,
хранятся в массиве B. При этом порядок их следования в массиве таков,
что вложенные блоки размещаются перед объемлющими их блоками. Это
следует из того факта, что на втором этапе алгоритма блоки добавлялись в
массив в порядке, обратном их следованию в массиве предложений обра-
ботки исключений (EH).
Присвоение родительских блоков узлам графа заключается в том, что
мы перебираем все элементы массива B по порядку, начиная с первого эле-
мента (в нем содержится информация о блоке тела метода). При этом для
каждого i-го элемента массива B мы выполняем следующую операцию:
каждый узел графа, имеющий в массиве Nodes индекс от B[i].offset до
B[i].offset+B[i].length-1, получает в качестве родителя блок B[i].block.
for (int i = 0; i < BN; i++)
{
for (int j = B[i].offset; j < B[i].offset+B[i].length; j++)
Сделать блок B[i].block родителем узла Nodes[j];
}
Таким образом, на первой итерации цикла родителем всех узлов ста-
новится блок тела метода (MBB), а на последующих итерациях некоторые
диапазоны инструкций меняют родителей, и это происходит до тех пор,
пока не будут рассмотрены все элементы массива B. В конце концов роди-
телями всех узлов становятся именно те блоки, в которые эти узлы непо-
средственно входят.
4.2.4. Формирование дуг
На четвертом этапе в граф потока управления добавляются дуги, обо-
значающие передачу управления между инструкциями.
Определенную трудность представляет необходимость включения в
граф потока управления узлов-блоков. Предварительным шагом для этого
служит создание специального массива blockNodes размера N и запись в
этот массив ссылок на блоки. При этом запись осуществляется следую-
щим образом: мы перебираем все структуры в массиве B и для каждой
i-ой структуры записываем в элемент массива blockNodes с индексом
B[i].offset ссылку B[i].block. В результате, для того, чтобы определить,
какой блок начинается с инструкции с номером k, достаточно посмотреть
k-тый элемент массива blockNodes.
Формирование массива blockNodes удобно совместить с проведением
дуг от узлов-блоков к узлам, соответствующим первым инструкциям этих
Анализ кода на CIL
145
/* Поиск в массиве B блока, диапазон инструкций которого содержит
защищенную областью i-го предложения */
int tryOffset = EH[i].TryOffset, tryLength = EH[i].TryLength;
for (int j = BN-1; j >= 0; j--)
if (tryOffset >= B[j].offset &&
tryOffset+tryLength <= B[j].offset+B[j].length)
break;
if (tryOffset != B[j].offset || tryLength != B[j].length)
{
/* Создание нового защищенного блока и
добавление его в дерево */
B[BN].block = новый защищенный блок;
Сделать блок B[j].block родителем блока B[BN].block;
B[BN].offset = tryOffset;
B[BN].length = tryLength;
j = BN; BN++;
}
/* Создание блока обработки исключений */
B[BN].block = новый блок обработки исключений,
тип которого определяется значением EH[i].Flags;
Сделать родителем блока B[BN].block тот же блок,
который является родителем блока B[j].block;
Добавить блок B[BN].block в конец списка
обработчиков, ассоциированных с блоком B[j].block;
B[BN].offset = EH[i].HandlerOffset;
B[BN].length = EH[i].HandlerLength;
BN++;
if (EH[i].Flags обозначает блок с пользовательской фильтрацией)
{
/* Создание блока фильтрации */
B[BN].block = новый блок фильтрации;
Сделать блок B[BN-1].block родителем блока B[BN].block;
B[BN].offset = EH[i].FilterOffset;
B[BN].length = EH[i].HandlerOffset – EH[i].FilterOffset;
BN++;
}
}
144
CIL и системное программирование в Microsoft .NET
144                            CIL и системное программирование в Microsoft .NET   Анализ кода на CIL                                                   145


          /* Поиск в массиве B блока, диапазон инструкций которого содержит        4.2.3. Присвоение родительских блоков узлам графа
             защищенную областью i-го предложения */
          int tryOffset = EH[i].TryOffset, tryLength = EH[i].TryLength;                 На третьем этапе узлы, соответствующие инструкциям, получают ро-
          for (int j = BN-1; j >= 0; j--)                                          дителей. Тем самым завершается построение дерева блоков.
            if (tryOffset >= B[j].offset &&                                             Можно заметить, что все блоки графа, включая блок тела метода,
               tryOffset+tryLength <= B[j].offset+B[j].length)                     хранятся в массиве B. При этом порядок их следования в массиве таков,
               break;                                                              что вложенные блоки размещаются перед объемлющими их блоками. Это
                                                                                   следует из того факта, что на втором этапе алгоритма блоки добавлялись в
          if (tryOffset != B[j].offset || tryLength != B[j].length)                массив в порядке, обратном их следованию в массиве предложений обра-
          {                                                                        ботки исключений (EH).
            /* Создание нового защищенного блока и                                      Присвоение родительских блоков узлам графа заключается в том, что
               добавление его в дерево */                                          мы перебираем все элементы массива B по порядку, начиная с первого эле-
            B[BN].block = новый защищенный блок;                                   мента (в нем содержится информация о блоке тела метода). При этом для
            Сделать блок B[j].block родителем блока B[BN].block;                   каждого i-го элемента массива B мы выполняем следующую операцию:
            B[BN].offset = tryOffset;                                              каждый узел графа, имеющий в массиве Nodes индекс от B[i].offset до
            B[BN].length = tryLength;                                              B[i].offset+B[i].length-1, получает в качестве родителя блок B[i].block.
            j = BN; BN++;                                                               for (int i = 0; i < BN; i++)
          }                                                                             {
                                                                                          for (int j = B[i].offset; j < B[i].offset+B[i].length; j++)
          /* Создание блока обработки исключений */                                          Сделать блок B[i].block родителем узла Nodes[j];
          B[BN].block = новый блок обработки исключений,                                }
          тип которого определяется значением EH[i].Flags;                              Таким образом, на первой итерации цикла родителем всех узлов ста-
          Сделать родителем блока B[BN].block тот же блок,                         новится блок тела метода (MBB), а на последующих итерациях некоторые
          который является родителем блока B[j].block;                             диапазоны инструкций меняют родителей, и это происходит до тех пор,
          Добавить блок B[BN].block в конец списка                                 пока не будут рассмотрены все элементы массива B. В конце концов роди-
          обработчиков, ассоциированных с блоком B[j].block;                       телями всех узлов становятся именно те блоки, в которые эти узлы непо-
          B[BN].offset = EH[i].HandlerOffset;                                      средственно входят.
          B[BN].length = EH[i].HandlerLength;
          BN++;                                                                    4.2.4. Формирование дуг
                                                                                        На четвертом этапе в граф потока управления добавляются дуги, обо-
          if (EH[i].Flags обозначает блок с пользовательской фильтрацией)          значающие передачу управления между инструкциями.
          {                                                                             Определенную трудность представляет необходимость включения в
            /* Создание блока фильтрации */                                        граф потока управления узлов-блоков. Предварительным шагом для этого
            B[BN].block = новый блок фильтрации;                                   служит создание специального массива blockNodes размера N и запись в
            Сделать блок B[BN-1].block родителем блока B[BN].block;                этот массив ссылок на блоки. При этом запись осуществляется следую-
            B[BN].offset = EH[i].FilterOffset;                                     щим образом: мы перебираем все структуры в массиве B и для каждой
            B[BN].length = EH[i].HandlerOffset – EH[i].FilterOffset;               i-ой структуры записываем в элемент массива blockNodes с индексом
            BN++;                                                                  B[i].offset ссылку B[i].block. В результате, для того, чтобы определить,
          }                                                                        какой блок начинается с инструкции с номером k, достаточно посмотреть
      }                                                                            k-тый элемент массива blockNodes.
                                                                                        Формирование массива blockNodes удобно совместить с проведением
                                                                                   дуг от узлов-блоков к узлам, соответствующим первым инструкциям этих