Почему разработчики Microsoft решили сделать.NET машиной на основе стека?

Сегодня я нашел дизассемблер IL между инструментами, поставляемыми с VS2008. Я попытался разобрать программу и посмотреть результат. Операционные коды было не так сложно понять, но меня удивило одно:.NET основан на стеке?! Чтение "Пиши отличный код, том II" Я не смог получить хорошее представление о машинах на основе стека, поскольку они довольно медленные. Их тоже легко реализовать, но я не думаю, что разработчики MS выбрали этот подход из-за его простоты, ведь этот код необходимо преобразовать в реальный машинный код, чтобы они просто переместили проблему.
Кто-нибудь из вас может объяснить этот странный выбор?

PS:
Я публикую здесь то, что я прочитал об этой теме:

13.1.1 Машины на основе стека Машины на основе стека используют память для большинства вычислений, используя стек в памяти для хранения всех операндов и результатов. Компьютерные системы, использующие стековую архитектуру, предлагают некоторые важные преимущества по сравнению с другими архитектурами:

  • Инструкции часто меньше (каждый занимает меньше байтов), чем в других архитектурах, потому что инструкции обычно не должны указывать какие-либо операнды.
  • Как правило, писать компиляторы для стековых архитектур проще, чем для других машин, потому что преобразование арифметических выражений в последовательность операций стека очень просто.
  • Временные переменные редко требуются в архитектуре стека, потому что сам стек служит для этой цели.
К сожалению, стековые машины также страдают некоторыми серьезными недостатками:
  • Почти каждая инструкция ссылается на память (что медленно на современных машинах). Хотя кеши могут помочь решить эту проблему, производительность памяти все еще остается серьезной проблемой на стековых машинах.
  • Даже несмотря на то, что преобразование из HLL в стековую машину очень просто, возможностей для оптимизации меньше, чем в других архитектурах.
  • Поскольку стековые машины постоянно обращаются к одним и тем же элементам данных (то есть данным, находящимся на вершине стека), трудно добиться конвейерной обработки и параллелизма команд (подробности о конвейерной обработке и параллелизме инструкций см. В статье Write Great Code, Volume 1).
Стек - это структура данных, которая позволяет выполнять операции только с несколькими ограниченными элементами стека (часто называемыми вершиной стека и следующими по стеку). Со стеком вы обычно делаете одну из трех вещей: помещаете новые данные в стек, извлекаете данные из стека или оперируете данными, которые в настоящее время находятся на вершине стека (и, возможно, данными непосредственно под ним).

а также

13.1.1.5 Реальные стековые машины
Большим преимуществом стековой архитектуры является то, что легко написать компилятор для такой машины. Также очень легко написать эмулятор для стековой машины. По этим причинам стековые архитектуры популярны в виртуальных машинах (ВМ), таких как виртуальная машина Java и интерпретатор p-кода Microsoft Visual Basic. Существует несколько реальных процессоров, основанных на стеке, таких как аппаратная реализация Java VM; однако они не очень популярны из-за ограничений производительности доступа к памяти. Тем не менее, понимание основ архитектуры стека важно, потому что многие компиляторы переводят исходный код HLL в основанную на стеке форму перед переводом в реальный машинный код. В самом деле, в худшем случае (хотя и редко) компиляторы вынуждены генерировать код, который эмулирует машину на основе стека при компиляции сложных арифметических выражений.

РЕДАКТИРОВАТЬ: Я только что нашел статью в блоге @EricLippert, отвечая на вопрос и подтверждая ответ @ Аарона

3 ответа

Решение

Имейте в виду, что только потому, что промежуточное представление основано на стеке, это не означает, что сгенерированный машинный код основан на стеке. Поскольку код преобразуется из промежуточной формы в машинный код, он в основном перекомпилируется - с учетом локальной оптимизации.

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

Представьте себе, если они решили использовать теоретическую систему на основе регистров в качестве промежуточной формы. Сколько регистров они должны выбрать? 8? 16? 64? Если у вашего целевого процессора больше фактических регистров, чем у промежуточной формы, то вы упустили возможные оптимизации. Если ваша цель имеет меньше фактических регистров, чем промежуточные, тогда ваши оптимизации контрпродуктивны, потому что эти регистры все равно сбрасываются в память.

Даже на современных процессорах у вас есть большая разница при компиляции до x86 против x64 - не говоря уже о альтернативных архитектурах (ARM) или будущих архитектурах.

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

Причина, по которой CIL основан на стеке, заключается в том, что он не предназначен для набора инструкций, предназначенных для виртуальной машины. Это промежуточный этап компиляции.

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

Вы должны были бы спросить разработчиков Microsoft. Но я предполагаю, что проблема производительности не была их главной задачей. Большинство приложений Windows не ограничены процессором или даже действительно ограничены вводом / выводом, так как они проводят большую часть своего времени в ожидании нажатия пользователем кнопки. Однако архитектура, которая позволяла бы им легко внедрять новые языки, вероятно, была приоритетом.

Другие вопросы по тегам