Московский государственный технический университет им. Н.Э. Баумана
Опубликован: 28.06.2006 | Доступ: свободный | Студентов: 12461 / 340 | Оценка: 4.54 / 3.83 | Длительность: 22:03:00
ISBN: 978-5-9556-0055-0
Лекция 8:

Анализ кода на CIL

Присвоение родительских блоков узлам графа

На третьем этапе узлы, соответствующие инструкциям, получают родителей. Тем самым завершается построение дерева блоков.

Можно заметить, что все блоки графа, включая блок тела метода, хранятся в массиве 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. В конце концов родителями всех узлов становятся именно те блоки, в которые эти узлы непосредственно входят.

Формирование дуг

На четвертом этапе в граф потока управления добавляются дуги, обозначающие передачу управления между инструкциями.

Определенную трудность представляет необходимость включения в граф потока управления узлов-блоков. Предварительным шагом для этого служит создание специального массива blockNodes размера N и запись в этот массив ссылок на блоки. При этом запись осуществляется следующим образом: мы перебираем все структуры в массиве B и для каждой i-ой структуры записываем в элемент массива blockNodes с индексом B[i].offset ссылку B[i].block. В результате, для того, чтобы определить, какой блок начинается с инструкции с номером k, достаточно посмотреть k-тый элемент массива blockNodes.

Формирование массива blockNodes удобно совместить с проведением дуг от узлов-блоков к узлам, соответствующим первым инструкциям этих блоков. Для этого нужно каждый блок, расположенный в массиве blockNodes по индексу i, соединить дугой с узлом Nodes[i]:

blockNodes = новый массив ссылок на узлы размера N,
	изначально заполненный нулевыми ссылками;
for (int i = 0; i < BN; i++)
{
  Провести дугу от B[i].block к Nodes[B[i].offset];
  blockNodes[B[i].offset] = B[i].block;
}

Добавление остальных дуг осуществляется путем перебора всех узлов, находящихся в массиве Nodes. Давайте рассмотрим, как это происходит для некоторого узла Nodes[i].

Прежде всего мы определяем номера инструкций, на которые может быть передано управление от инструкции, соответствующей узлу Nodes[i]. Естественно, для этого должна учитываться семантика инструкции. Полученные номера инструкций записываются в массив Flow.

Затем для каждого номера n, входящего в массив Flow, мы проводим дугу от узла Nodes[i] к соответствующему номеру n узлу графа:

  • это узел blockNodes[n] в том случае, если blockNodes[n] содержит ссылку на блок (то есть если инструкция под номером n является первой инструкцией некоторого блока) и Nodes[i] непосредственно или транзитивно принадлежит этому блоку;
  • это узел Nodes[n] в противном случае.

На псевдоязыке это выглядит следующим образом:

for (int i = 0; i < N; i++)
{
  int[] Flow = новый массив, в который добавляются 
		 номера инструкций, на которые может быть передано
		 управление от инструкции, соответствующей узлу 
		 Nodes[i];
  for (int j = 0; j < Flow.Length; j++)
  {
    int n = Flow[j];
    if (blockNodes[n] != null && blockNodes[n] не является 
	      непосредственно или транзитивно родителем узла Nodes[i])
       Провести дугу от Nodes[i] к blockNodes[n];
    else
       Провести дугу от Nodes[i] к Nodes[n];
  }
}
Анастасия Булинкова
Анастасия Булинкова
Рабочим названием платформы .NET было