Вопрос

Я наблюдал много "стекового интроспективного" кода в приложениях, которые часто неявно полагаются на содержащие их методы нет быть уверенным в их правильности.Такие методы обычно включают вызовы:

  • MethodBase.GetCurrentMethod
  • Assembly.GetCallingAssembly
  • Assembly.GetExecutingAssembly

Теперь я нахожу информацию, связанную с этими методами, очень запутанной.Я слышал, что во время выполнения не будет встроен метод, вызывающий GetCurrentMethod, но я не могу найти никакой документации на этот счет.Я несколько раз видел сообщения о StackOverflow, такие как этот, указывающий, что среда CLR не выполняет встроенных вызовов перекрестной сборки, но GetCallingAssembly Документация убедительно указывает на обратное.

Есть также сильно оклеветанные [MethodImpl(MethodImplOptions.NoInlining)], но я не уверен, считает ли среда CLR это "запросом" или "командой".

Обратите внимание, что я спрашиваю о встраивании приемлемость с точки зрения контракта, нет о том, когда текущие реализации джиттера отказываются рассматривать методы из-за трудностей реализации, или о том, когда джиттер, наконец, заканчивается выбирая внедрить приемлемый метод после оценки компромиссов.Я читал это и это, но они, похоже, больше сосредоточены на последних двух пунктах (есть мимолетные упоминания о MethodImpOptions.NoInlining и "экзотических инструкциях IL", но они, похоже, представлены как эвристика, а не как обязательства).

Когда будет CLR разрешенный встроить?

Это было полезно?

Решение

Это деталь реализации Jitter, у x86 и x64 -re -jitters имеют тонко разные правила. Это случайно задокументировано в постах блога членов команды, которые работали над джиттер, но команды, безусловно, оставляют за собой право изменять правила. Похоже, вы уже нашли их.

Методы внедрения из других собраний, безусловно, поддерживаются, многие классы .NET работают совершенно с треском, если бы это было не так. Вы можете увидеть это на работе, когда вы смотрите на машинный код, сгенерированный для консоли. Чтобы увидеть это для себя, вам нужно перейти на сборку релиза и изменить вариант отладчика. Инструменты + опции, отладка, общая, распуская «Подавить оптимизацию JIT на загрузку модуля».

В противном случае нет веских оснований считать MethodImpoption. Несовершеннолетняя, в основном он существует в первую очередь. На самом деле он намеренно используется в .NET Framework на множестве небольших публичных методов, которые называют внутренний вспомогательный метод. Это облегчает диагностику стека исключений.

Другие советы

Несмотря на ответ Ганса Пассанта, здесь сначала пара подсказок по состоянию на 2004 год, а далее еще немного актуальной информации.Они могут быть изменены, но они дают вам представление о том, на что следует обратить внимание, если вы хотите сделать метод пригодным для встраивания:

JIT не будет встроен:

  • Методы, помеченные параметром MethodImplOptions.Нет вставки
  • Методы размером более 32 байт IL
  • Виртуальные методы
  • Методы, принимающие в качестве параметра большой тип значения
  • Методы в классах MarshalByRef
  • Методы со сложными блок - схемами
  • Методы, отвечающие другим, более экзотическим критериям

В частности, существует Варианты метода.Агрессивный подход, который, как предполагается, отменит ограничение в 32 байта (или что бы это ни было в наши дни и для вашей платформы).

.Net 3.5 добавил эвристику, которая помогает определить, является ли Встроить или не встроить, что, вероятно, хорошо, хотя разработчику сложнее предсказать решение джиттера:

Цитата из статьи:

  1. Если встраивание делает код меньше, чем заменяемый им вызов, это ВСЕГДА хорошо.Обратите внимание, что мы говорим о размере СОБСТВЕННОГО кода, а не о размере IL-кода (который может сильно отличаться).

  2. Чем чаще выполняется конкретный сайт вызова, тем больше он выиграет от inlning.Таким образом, код в циклах заслуживает того, чтобы быть встроенным больше , чем код, который не находится в циклах.

  3. Если встраивание предоставляет важные оптимизации, то встраивание более желательно.В частности, методы с аргументами типов значений выигрывают больше, чем обычно, из-за подобных оптимизаций и, следовательно, склонность к встроению этих методов хороша.

Таким образом, эвристика, которую использует компилятор X86 JIT, - это встроенный кандидат .

  1. Оцените размер сайта вызова, если бы метод не был встроен.

  2. Оцените размер сайта вызова, если бы он был встроенным (это оценка, основанная на IL, мы используем простой конечный автомат (марковскую модель ), созданный с использованием большого количества реальных данных для формирования этой логики оценки)

  3. Вычислите множитель.По умолчанию оно равно 1

  4. Увеличьте множитель, если код находится в цикле (текущая эвристика увеличивает его до 5 в цикле).

  5. Увеличьте множитель, если кажется, что начнется оптимизация структуры.

  6. Если InlineSize <= NonInlineSize * Множитель выполняет встраивание.

Пока Ответ Ганса правильно, есть одно упущение, не обязательно о том, когда метод имеет право на внедрение, но когда метод нет.

Аннотация и виртуальные методы не имеют права на внедрение в CLR.

Важно отметить, когда оно снижает условия, в которых метод мая быть вставленным.

Есть больше информации об внедрении методического базы. GetCurrentMethod в этой теме http://prdlxvm0001.codify.net/pipermail/ozdotnet/2011-march/009085.html

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

Кроме того, Assembly.getCallingAssembly и Assembly. Методы GetExeCutingAssembly не имеют этого атрибута.

В 2003 году была опубликована статья на MSDN под названием под названием под названием « Написание высокопроизводительных управляемых приложений Это довольно четко охватывает несколько критериев:

  • Методы, которые превышают 32 байта IL, не будут вставлены.
  • Виртуальные функции не вставлены.
  • Методы, которые имеют сложный контроль потока, не будут встроенными. Комплексное управление потоком - это какое -либо управление потоком, кроме if/then/else; В этом случае переключатель или пока.
  • Методы, которые содержат блоки обработки исключений, не вставлены, хотя методы, которые бросают исключения по-прежнему кандидатами для внедрения.
  • Если какой -либо из формальных аргументов метода являются структурой, метод не будет вставлен.

Статья в блоге Sacha Goldshtein в 2012 году на агрессивное внедрение в CLR имеет много такого же совета.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top