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

UptoLike

Давайте сформулируем эти ограничения:
1. Ограничение на структуру стека вычислений.
Структура стека вычислений определяется количеством и типа-
ми значений, лежащих на стеке.
Для любой инструкции, входящей в поток инструкций, структу-
ра стека должна быть постоянной вне зависимости от того, из
какого места программы на нее передается управление.
2. Ограничение на размер стека вычислений.
В заголовке метода должна быть указана максимальная глубина
стека вычислений. Другими словами, максимальное количество
значений, которое может размещаться на стеке вычислений в
процессе выполнения метода, должно быть заранее известно
еще до JIT-компиляции этого метода.
Это ограничение, на первый взгляд, может показаться несколь-
ко странным, если принять во внимание, что благодаря ограни-
чению 1 JIT-компилятор может легко вычислить максимальную
глубину стека в процессе компиляции. Цель введения подобно-
го ограничения состоит в том, чтобы JIT-компилятор, присту-
пая к компиляции метода, мог сразу выделить нужное количест-
во памяти под свои внутренние структуры данных.
3. Ограничение на обратные переходы.
Если при последовательном переборе инструкций, формирую-
щих тело метода, JIT-компилятор встречает инструкцию, рас-
положенную сразу за инструкцией безусловного перехода, и ес-
ли на эту инструкцию еще не было перехода, то JIT-компилятор
не может вычислить структуру стека вычислений для этой инст-
рукции. В этом случае он предполагает, что стек для этой инст-
рукции должен быть пуст.
Чтобы лучше понять данную ситуацию, рассмотрим пример:
...
br L2
L1: ldc.0 ; здесь стек считается пустым
...
L2: br L1 ; обратный переход на L1
...
Когда JIT-компилятор доходит до инструкции ldc.0, расположен-
ной непосредственно после инструкции безусловного перехода br
L2, он не может определить для нее структуру стека вычислений,
так как еще не дошел до того места программы, откуда на нее пе-
редается управление. В принципе, просканировав дальше про-
грамму, это место можно обнаружить (это инструкция br L1), но
тогда алгоритм JIT-компилятора должен быть многопроходным.
Common Intermediate Language
87
3.1.1.2. Адреса переходов
В состав набора инструкций CIL входят инструкции для организации
условных и безусловных переходов. Встроенные операнды этих инструк-
ций содержат адреса переходов. При этом допустимы только такие адреса,
которые указывают на первые байты инструкций в теле данного метода.
Мы будем называть абсолютным адресом инструкции смещение пер-
вого байта инструкции относительно начала потока инструкций. Инст-
рукцию, на которую передается управление в результате выполнения ин-
струкции перехода, назовем целью перехода.
В качестве адресов перехода используются не абсолютные адреса це-
лей перехода, а так называемые относительные адреса. Относительный ад-
рес является разностью абсолютного адреса цели перехода и абсолютного
адреса инструкции, непосредственно следующей за инструкцией перехо-
да. Для того чтобы лучше понять принцип вычисления адресов перехода,
обратимся к следующему примеру:
...
target_addr: add ; цель перехода
...
br rel_addr ; инструкция перехода
next_addr: ...
Здесь используется инструкция безусловного перехода br. При этом в
качестве цели перехода выступает инструкция add, расположенная по аб-
солютному адресу target_addr. Если инструкция, следующая за инструк-
цией br, имеет абсолютный адрес next_addr, то адрес перехода rel_addr
вычисляется следующим образом:
reladdr := target_addr – next_addr
Адреса переходов кодируются во встроенных операндах инструкций
перехода в виде 8-битных или 32-битных целых чисел со знаком. При этом
8-битные адреса используются в сокращенных вариантах инструкций пе-
рехода.
3.1.1.3. Ограничения на последовательности инструкций
В спецификации языка CIL в описании каждой инструкции указаны
условия, при которых допустимо ее использование. Кроме того, на форми-
рование последовательности инструкций наложен ряд ограничений, поз-
воляющих упростить создание JIT-компилятора. Наличие этих ограниче-
ний означает, что в программах допускаются не любые сочетания инструк-
ций, а только те сочетания, которые удовлетворяют некоторым условиям.
Упрощение JIT-компилятора благодаря введению ограничений на
последовательности инструкций достигается, главным образом, за счет
того, что эти ограничения позволяют использовать в JIT-компиляторе од-
нопроходный алгоритм перевода CIL-кода в код процессора.
86
CIL и системное программирование в Microsoft .NET
86                         CIL и системное программирование в Microsoft .NET   Common Intermediate Language                                          87


3.1.1.2. Адреса переходов                                                           Давайте сформулируем эти ограничения:
     В состав набора инструкций CIL входят инструкции для организации                 1. Ограничение на структуру стека вычислений.
условных и безусловных переходов. Встроенные операнды этих инструк-                      Структура стека вычислений определяется количеством и типа-
ций содержат адреса переходов. При этом допустимы только такие адреса,                   ми значений, лежащих на стеке.
которые указывают на первые байты инструкций в теле данного метода.                      Для любой инструкции, входящей в поток инструкций, структу-
     Мы будем называть абсолютным адресом инструкции смещение пер-                       ра стека должна быть постоянной вне зависимости от того, из
вого байта инструкции относительно начала потока инструкций. Инст-                       какого места программы на нее передается управление.
рукцию, на которую передается управление в результате выполнения ин-                  2. Ограничение на размер стека вычислений.
струкции перехода, назовем целью перехода.                                               В заголовке метода должна быть указана максимальная глубина
     В качестве адресов перехода используются не абсолютные адреса це-                   стека вычислений. Другими словами, максимальное количество
лей перехода, а так называемые относительные адреса. Относительный ад-                   значений, которое может размещаться на стеке вычислений в
рес является разностью абсолютного адреса цели перехода и абсолютного                    процессе выполнения метода, должно быть заранее известно
адреса инструкции, непосредственно следующей за инструкцией перехо-                      еще до JIT-компиляции этого метода.
да. Для того чтобы лучше понять принцип вычисления адресов перехода,                     Это ограничение, на первый взгляд, может показаться несколь-
обратимся к следующему примеру:                                                          ко странным, если принять во внимание, что благодаря ограни-
                    ...                                                                  чению 1 JIT-компилятор может легко вычислить максимальную
     target_addr: add           ; цель перехода                                          глубину стека в процессе компиляции. Цель введения подобно-
                    ...                                                                  го ограничения состоит в том, чтобы JIT-компилятор, присту-
                    br rel_addr ; инструкция перехода                                    пая к компиляции метода, мог сразу выделить нужное количест-
     next_addr: ...                                                                      во памяти под свои внутренние структуры данных.
     Здесь используется инструкция безусловного перехода br. При этом в               3. Ограничение на обратные переходы.
качестве цели перехода выступает инструкция add, расположенная по аб-                    Если при последовательном переборе инструкций, формирую-
солютному адресу target_addr. Если инструкция, следующая за инструк-                     щих тело метода, JIT-компилятор встречает инструкцию, рас-
цией br, имеет абсолютный адрес next_addr, то адрес перехода rel_addr                    положенную сразу за инструкцией безусловного перехода, и ес-
вычисляется следующим образом:                                                           ли на эту инструкцию еще не было перехода, то JIT-компилятор
     reladdr := target_addr – next_addr                                                  не может вычислить структуру стека вычислений для этой инст-
     Адреса переходов кодируются во встроенных операндах инструкций                      рукции. В этом случае он предполагает, что стек для этой инст-
перехода в виде 8-битных или 32-битных целых чисел со знаком. При этом                   рукции должен быть пуст.
8-битные адреса используются в сокращенных вариантах инструкций пе-                      Чтобы лучше понять данную ситуацию, рассмотрим пример:
рехода.                                                                                        ...
                                                                                               br L2
3.1.1.3. Ограничения на последовательности инструкций                                   L1: ldc.0 ; здесь стек считается пустым
     В спецификации языка CIL в описании каждой инструкции указаны                             ...
условия, при которых допустимо ее использование. Кроме того, на форми-                  L2: br L1 ; обратный переход на L1
рование последовательности инструкций наложен ряд ограничений, поз-                            ...
воляющих упростить создание JIT-компилятора. Наличие этих ограниче-                      Когда JIT-компилятор доходит до инструкции ldc.0, расположен-
ний означает, что в программах допускаются не любые сочетания инструк-                   ной непосредственно после инструкции безусловного перехода br
ций, а только те сочетания, которые удовлетворяют некоторым условиям.                    L2, он не может определить для нее структуру стека вычислений,
     Упрощение JIT-компилятора благодаря введению ограничений на                         так как еще не дошел до того места программы, откуда на нее пе-
последовательности инструкций достигается, главным образом, за счет                      редается управление. В принципе, просканировав дальше про-
того, что эти ограничения позволяют использовать в JIT-компиляторе од-                   грамму, это место можно обнаружить (это инструкция br L1), но
нопроходный алгоритм перевода CIL-кода в код процессора.                                 тогда алгоритм JIT-компилятора должен быть многопроходным.