Цифровой журнал «Компьютерра» 2011 № 44 (92) | страница 2
Конечно, программисты были влюблены в этот инструмент создания программ, представленный С и его последователями. А вот с исполнением полученного кода на конкретном «железе» всё было далеко не так гладко. Перефразируя поэта, можно сказать: «Любовная лодка эффективности языка программирования разбилась о быт процессорных архитектур». В чём же крылась причина этого кораблекрушения?
Вспомним в общих чертах, как процессор выполняет программу. Все необходимые для работы программы компоненты, а именно код и данные, располагаются в определённом адресном пространстве оперативной памяти. Процессоры, как правило, избегают обращаться к оперативной памяти напрямую, поскольку считается, что это сильно замедляет их работу. Поэтому в состав процессора входит специальный модуль вызова команд, который занимается выборкой инструкций программы из оперативной памяти и передаёт найденные инструкции исполнительному устройству процессора. В подавляющем большинстве случаев модуль вызова команды размещает найденную инструкцию и данные для обработки в специальные регистры процессора, к которым имеет доступ исполнительное устройство.
Фактически процессор классической архитектуры (неважно, CISC или RISC) общается только с этими регистрами, знать не зная о том, что же происходит в памяти. Конечно же, у такой схемы обработки есть варианты. Например, регистры могут быть заменены или дополнены аппаратно реализованным пулом в виде очереди FIFO или же специальной кэш-памятью. Эти изменения и дополнения позволяют модулю вызова команды осуществлять предварительную выборку сразу нескольких инструкций, подыгрывая суперскалярности исполнительного устройства. Однако регистровая суть работы процессора при этом не меняется.
Беда же заключается в том, что языки программирования высокого уровня, подобные С (ассемблеры, вплотную приближенные к архитектуре процессора, не в счёт), создавая программу, используют совершенно другую методологию. Они размещают необходимые программе локальные переменные и иные структуры, необходимые для выполнения основной ветви программы и вызываемых из неё процедур, в области памяти, называемой «стек». Стек устроен по принципу оружейного магазина и на своей вершине содержит наиболее актуальные в данный момент данные.
Одним словом, стековая идиллия программ, которую создаёт компилятор, сталкивается с суровыми регистровыми буднями реальных процессорных архитектур. В этом не было бы ничего страшного, если бы не вызовы процедур.