2014-01-07 3 views
4

Я написал компилятор, который генерирует IL, используя System.Reflection.Emit. Это отлично работает для кода, но я не знаю, как испускать большие инициализированные таблицы, которые мне также необходимо включить. Вся суть компилятора заключается в том, чтобы сгенерировать эти таблицы, и невозможно вычислить инициализаторы во время выполнения.Инициализация большого количества данных в IL

Я попытался сохранить данные инициализации в строках, загружаемых с использованием Ldstr, но оказалось, что существует жесткий предел времени, в течение которого могут быть получены эти строки.

Я также попытался испустить код, который выделяет массив, затем назначает инициализаторы (a [0] = const0; a [1] = const1; a [2] = const2, ...). Это работает, но, похоже, замедляет выполнение, даже если оно выполняется только один раз при инициализации. Я предполагаю, что компилятор JIT не очень похож на много линейного кода.

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

Что такое «обычный» способ инициализации большого количества данных в .net, пожалуйста?

+0

Что такое «большой»? И какие типы задействованы? – rene

+0

Посмотрите, как это делает компилятор C#. Есть трюк. – usr

+0

Большой - 10 МБ. Но в идеале я хотел бы что-то, что еще больше. –

ответ

3

Посмотрите, как C# инициализирует статические массивы типов значений. (Это может работать только с ценностями). IT создает класс в - пространство имен, где <module> находится, называется <PrivateImplementationDetails>{GUID_OF_YOUR_ASSEMBLY}

В этом классе он создает на структуру, чтобы инициализировать массив с помощью атрибута:

[StructLayout(LayoutKind.Explicit, Size=SIZE_OF_ARRAY_IN_BYTES, Pack=1)] 
private struct __StaticArrayInitTypeSize=SIZE_OF_ARRAY_IN_BYTES 
{ 
} 

Где SIZE_OF_ARRAY_IN_BYTES это число байтов для элемент умножает длину массива. (например, int[] foo={0,1,2,3,4,5,6,7,8,9} будет размером = 40)

В сборке он присваивает двоичное представление массива внутреннему статическому полю readonly в <PrivateImplementationDetails>.

Наконец, он загружает runtimefield ручку в поле, держащего тело массивов, и вызывает метод System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray

К сожалению, в документации по этому методу ужасно. Похоже, вы передаете ему массив, а затем передаете его в поле. IL для моего примера статического инициализатора выглядит так: надеюсь, что это поможет:

.method private hidebysig specialname rtspecialname static void .cctor() cil managed 
{ 
    .maxstack 8 
    L_0000: ldc.i4.s 0x15 
    L_0002: newarr int32 
    L_0007: dup 
    L_0008: ldtoken valuetype <PrivateImplementationDetails>{D28836D0-542D-4735-8815-954F79B1D29C}/__StaticArrayInitTypeSize=84 <PrivateImplementationDetails>{D28836D0-542D-4735-8815-954F79B1D29C}::$$method0x6000003-1 
    L_000d: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle) 
    L_0012: stsfld int32[] Test.Program::vals 
    L_0017: ret 
} 
+0

Большое спасибо. Я не думаю, что вам может показаться, что Google узнает, как испускать бит, который говорит: «В сборке он присваивает двоичное представление»? Я пробовал смотреть в Assemblybuilder, но нет ничего очевидного. Остальное кажется достаточно ясным и должно быть достаточно легко испускать. Еще раз спасибо! –

+1

Этот блог рассказывает об этом немного, похоже, вы используете 'ModuleBuilder.DefineInitializedData' http://weblog.ikvm.net/PermaLink.aspx?guid=33aed348-a990-40bd-9a01-7b903b918b55 –

Смежные вопросы