Самораскрутка и неподвижная точка
Компилятор Оберона написан на Обероне. Значит, чтобы его собрать, нужен компилятор Оберона. Это не парадокс, а обычная самораскрутка — но у неё есть проверяемое следствие, которое стоит понять точно, потому что его регулярно путают.
Что самораскрутка не доказывает
Фраза «компилятор собирает сам себя» сама по себе не значит ничего. Компилятор с ошибкой тоже соберёт сам себя — просто выдаст неверный код, а поскольку проверять некому, ошибка останется незамеченной.
Что доказывает неподвижная точка
Настоящая проверка выглядит иначе. Возьмём компилятор, лежащий на диске, — назовём его поколение 0 — и соберём им его собственные исходники. Получится поколение 1. Теперь выгрузим старый компилятор из памяти, загрузим поколение 1 и соберём им те же самые исходники ещё раз. Получится поколение 2.
Если поколения 1 и 2 совпадают побайтово — достигнута неподвижная точка.
Почему это содержательно. Поколение 1 собрано старым двоичным кодом, поколение 2 — новым. Если бы новый компилятор порождал хоть чуть-чуть другой код, чем старый, поколения разошлись бы. Совпадение означает, что преобразование «исходник → двоичный код» устойчиво: применённое к результату самого себя, оно ничего не меняет.
Это не доказывает, что компилятор правильный. Это доказывает, что он согласован сам с собой, и что собранный им компилятор ведёт себя так же, как тот, которым его собрали.
Как это выглядит на экране
В лабораторной №7 вы запускаете один модуль, но полный опыт делается так же — двумя блоками в журнале:
OR Compiler 18.4.2016
compiling ORS 1756 992 76547166
compiling ORB 2325 408 2F03B698
compiling ORG 6650 34980 8F476858
compiling ORP 6188 144 E6FCC519
System.Free
ORP unloading
ORG unloading
ORB unloading
ORS unloading
OR Compiler 18.4.2016
compiling ORS 1756 992 76547166
compiling ORB 2325 408 2F03B698
compiling ORG 6650 34980 8F476858
compiling ORP 6188 144 E6FCC519
Совпали размеры кода, размеры данных и ключи всех четырёх модулей. Строка
OR Compiler 18.4.2016 напечатана во втором блоке заново: это новый
ORP.rsc, загруженный с диска, объявляет себя. То есть второе поколение
действительно собрано свежими двоичными файлами, а не оставшимися в памяти
старыми — без System.Free опыт был бы бессмысленным.
Весь прогон — 715 миллионов инструкций и 1,1 миллиарда тактов на просимулированном железе.
Где в этой системе остаётся C
Честный ответ: в двух местах, и оба вне машины.
Симулятор. Verilator переводит Verilog в C++, и этот C++ исполняет логику процессора. Но это не реализация RISC5 — это исполнение его описания. На ПЛИС того же Verilog никакого C нет.
Мост к файловой системе хоста. Когда компилятор запускается не внутри системы, а прямо на ядре, ему нужен кто-то, кто отдаст файлы. Это обвязка на C, и она подменяет только файловую систему, ничего не считая сама.
В браузерной версии и этого моста нет: там файлы живут в образе диска, а компилятор запускается изнутри системы, мышью и клавиатурой. Кода на C в контуре не остаётся вовсе.
Пересборка всей системы
Компилятор — только четыре модуля из сорока двух. Полный опыт — пересобрать
систему целиком: Kernel, Files, Display, Viewers, Texts, Oberon,
редактор, графику, сам компилятор. И сравнить результат с тем, что лежало на
диске.
Мы это сделали. Тридцать семь объектных файлов совпали побайтово, пересобранный образ загружается и даёт ту же контрольную сумму экрана. Три модуля не компилируются, а один поставляемый файл устарел — про это в главе про модули.
Ловушка в проверке
Напоследок — методическое замечание, полезное далеко за пределами Оберона.
Первая версия нашей проверки сравнивала образы диска побайтово и радостно сообщала «неподвижная точка достигнута». Потом выяснилось, что она так же радостно проходит на нетронутом образе, где пересборка вообще не запускалась. Побайтовое сравнение не отличает «пересобрано и совпало» от «не трогали».
Даты файлов не спасали: часов у этой машины нет, и все отметки нулевые.
Починилось положительными признаками: после настоящей пересборки на диске
обязаны появиться PIO.rsc и PIO.smb, которых там не было, и обязан
измениться Math.rsc. Их отсутствие теперь считается провалом, а не
послаблением.
Мораль: проверка, которая не умеет провалиться, ничего не проверяет. Прежде чем верить зелёной галочке, сломайте то, что она стережёт, и убедитесь, что она покраснела.