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

UptoLike

Глава 5.
Динамическая генерация кода
5.1. Введение в динамическую генерацию кода
Динамическая генерация кода – это прием программирования, за-
ключающийся в том, что фрагменты кода порождаются и запускаются
непосредственно во время выполнения программы. Этот прием был изве-
стен достаточно давно, но усложнение архитектуры компьютеров, и, что
особенно важно, усложнение наборов команд процессоров привело к то-
му, что в последние 10-15 лет динамическая генерация кода в некоторой
степени потеряла популярность.
Целью динамической генерации кода является использование ин-
формации, доступной только во время выполнения программы, для повы-
шения качества исполняемого кода. В терминах метавычислений можно
сказать, что динамическая генерация кода позволяет специализировать
фрагменты программы по данным, известным во время выполнения.
В некотором смысле, любой JIT-компилятор как раз использует ди-
намическую генерацию кода: имея некоторую программу, записанную на
промежуточном языке (байт-коде), и зная, какой процессор работает в си-
стеме, JIT-компилятор динамически транслирует программу в инструк-
ции этого процессора. При этом можно считать, что тип процессора – эта
как раз та часть информации, которая становится известной только во
время выполнения программы.
Естественно, не стоит чересчур увлекаться динамической генерацией
кода: этот прием далеко не всегда дает ускорение программы. Можно ска-
зать, что применение динамической генерации оправдано, если:
1. процесс вычислений в некотором фрагменте программы
преимущественно определяется информацией, известной толь-
ко во время выполнения;
2. запуск этого фрагмента осуществляется многократно;
3. выполнение фрагмента связано с существенными затратами
времени процессора.
В .NET доступно два способа организации динамической генерации
кода:
1. порождение программы на языке C# и вызов компилятора C#;
2. непосредственное порождение метаданных и CIL-кода.
Динамическая генерация кода
163
);
MethodBuilder mainMethod =
module.DefineGlobalMethod(
“main”,
MethodAttributes.Static |
MethodAttributes.Public,
typeof(void),
null
);
MethodInfo ConsoleWriteLineMethod =
((typeof(Console)).GetMethod(“WriteLine”,
new Type[] { typeof(string) } ));
ILGenerator il = mainMethod.GetILGenerator();
il.Emit(OpCodes.Ldstr,”Hello, World!”);
il.Emit(OpCodes.Call,ConsoleWriteLineMethod);
il.Emit(OpCodes.Ret);
module.CreateGlobalFunctions();
assembly.SetEntryPoint(
mainMethod,PEFileKinds.ConsoleApplication
);
assembly.Save(“hello.exe”);
}
}
4.4.3. Сравнение возможностей библиотек
Возможности, предоставляемые библиотекой Metadata Unmanaged
API и библиотекой рефлексии, представлены в таблице 4.3.
Таблица 4.3. Сравнение возможностей библиотек
Из таблицы следует, что ни одна из библиотек, поставляемых вместе
с .NET Framework, не позволяет читать CIL-код, хотя эта возможность
требуется целому ряду метаинструментов (например, верификаторам и
оптимизаторам кода).
162
CIL и системное программирование в Microsoft .NET
Metadata Unmanaged API Reflection API
Чтение метаданных + +
Генерация метаданных + +
Чтение CIL-кода
Генерация CIL-кода +
162                             CIL и системное программирование в Microsoft .NET   Динамическая генерация кода                                         163


                   );
              MethodBuilder mainMethod =                                            Глава 5.
                module.DefineGlobalMethod(
                   “main”,                                                          Динамическая генерация кода
                   MethodAttributes.Static |
                      MethodAttributes.Public,
                   typeof(void),
                   null                                                             5.1. Введение в динамическую генерацию кода
                   );
              MethodInfo ConsoleWriteLineMethod =                                         Динамическая генерация кода – это прием программирования, за-
                ((typeof(Console)).GetMethod(“WriteLine”,                           ключающийся в том, что фрагменты кода порождаются и запускаются
                   new Type[] { typeof(string) } ));                                непосредственно во время выполнения программы. Этот прием был изве-
              ILGenerator il = mainMethod.GetILGenerator();                         стен достаточно давно, но усложнение архитектуры компьютеров, и, что
              il.Emit(OpCodes.Ldstr,”Hello, World!”);                               особенно важно, усложнение наборов команд процессоров привело к то-
              il.Emit(OpCodes.Call,ConsoleWriteLineMethod);                         му, что в последние 10-15 лет динамическая генерация кода в некоторой
              il.Emit(OpCodes.Ret);                                                 степени потеряла популярность.
              module.CreateGlobalFunctions();                                             Целью динамической генерации кода является использование ин-
              assembly.SetEntryPoint(                                               формации, доступной только во время выполнения программы, для повы-
                mainMethod,PEFileKinds.ConsoleApplication                           шения качества исполняемого кода. В терминах метавычислений можно
                );                                                                  сказать, что динамическая генерация кода позволяет специализировать
              assembly.Save(“hello.exe”);                                           фрагменты программы по данным, известным во время выполнения.
          }                                                                               В некотором смысле, любой JIT-компилятор как раз использует ди-
      }                                                                             намическую генерацию кода: имея некоторую программу, записанную на
                                                                                    промежуточном языке (байт-коде), и зная, какой процессор работает в си-
4.4.3. Сравнение возможностей библиотек                                             стеме, JIT-компилятор динамически транслирует программу в инструк-
     Возможности, предоставляемые библиотекой Metadata Unmanaged                    ции этого процессора. При этом можно считать, что тип процессора – эта
API и библиотекой рефлексии, представлены в таблице 4.3.                            как раз та часть информации, которая становится известной только во
                                                                                    время выполнения программы.
      Таблица 4.3. Сравнение возможностей библиотек                                       Естественно, не стоит чересчур увлекаться динамической генерацией
                                                                                    кода: этот прием далеко не всегда дает ускорение программы. Можно ска-
                             Metadata Unmanaged API        Reflection API
                                                                                    зать, что применение динамической генерации оправдано, если:
Чтение метаданных                      +                          +                          1. процесс вычислений в некотором фрагменте программы
Генерация метаданных                   +                          +                             преимущественно определяется информацией, известной толь-
Чтение CIL-кода                        –                          –                             ко во время выполнения;
Генерация CIL-кода                     –                          +                          2. запуск этого фрагмента осуществляется многократно;
                                                                                             3. выполнение фрагмента связано с существенными затратами
     Из таблицы следует, что ни одна из библиотек, поставляемых вместе                          времени процессора.
с .NET Framework, не позволяет читать CIL-код, хотя эта возможность                       В .NET доступно два способа организации динамической генерации
требуется целому ряду метаинструментов (например, верификаторам и                   кода:
оптимизаторам кода).                                                                         1. порождение программы на языке C# и вызов компилятора C#;
                                                                                             2. непосредственное порождение метаданных и CIL-кода.