Когда эмулятор собирает и компилирует код jit, то как он этот код в машинных инструкциях составляет.
Если ты посмотришь на QEMU, то у него есть фронт-енды (
https://github.com/qemu/qemu/tree/v8.1.0/target), каждый из которых транслирует инструкции эмулируемой машины в промежуточный код. И есть бэк-енды (
https://github.com/qemu/qemu/tree/v8.1.0/tcg), каждый из которых транслирует инструкции промежуточного кода в инструкции хостовой машины. Каждая гостевая инструкция может превратиться во множество промежуточных, а каждая промежуточная -- во множество хостовых. У разработчиков есть правило, что если на гостевую инструкцию требуется больше 20 промежуточных, то вместо прямой трансляции такая инструкция реализуется как вызов функции на C. Инструкции транслируются базовыми блоками, с заданного адреса и до достижения одного из следующих условий: 1) встречена инструкция выполняющая переход (условный или безусловный, вызов функции, возврат из функции, сюда же относятся инструкции гарантированно вызывающие исключение), или 2) PC переходит через границу страницы виртуальной памяти, или 3) количество инструкций в базовом блоке превышает заданный предел. Вдобавок с каждым оттранслированным базовым блоком ассоциируется дополнительный набор флагов, определяемый фронт-ендом, который кодирует состояние, в котором была машина при трансляции этого кода. Это позволяет иметь несколько вариантов трансляции для кода начинающегося с одного и того же адреса, например для разных уровней привилегий. Оттранслированные базовые блоки помещаются в кеш с функцией поиска по комбинации адреса и дополнительного набора флагов. В
цикле выполнения эмулятор
ищет транслированный базовый блок кода в кеше (а если не находит его, то
транслирует и помещает в кеш),
запускает его и получает контроль после завершения его выполнения.
надо к примеру Перед выполнением каждой инструкции проверять наличие прерывания
Вовсе не каждой, даже в 100% точной эмуляции нужно проверять IRQ только когда прерывания разрешены. QEMU обычно проверяет запрос на прерывание только перед входом в оттранслированный базовый блок.
Или же есть несколько блоков, где линейно выполняется весь блок, а последняя инструкция прыгнет в другой блок.
Да, QEMU выполняет трансляцию базовыми блоками.
к примеру для вот такого примера графа, сколько базовых блоков можно построить?
В этом графе не обозначены безусловные переходы, если их нет, то QEMU мог бы выделить такие базовые блоки:
0-1-2-3
,
4-5-6
,
7-8-1-2-3
,
9-10
,
11-12-13
,
14-15-16-2-3
,
17
, всего 7 блоков.
Если безусловные переходы -- это все переходы от узлов с бОльшими номерами к узлам с меньшими, то картина была бы такой:
0-1-2-3
,
4-5-6
,
7-8
,
1-2-3
,
9-10
,
11-12-13
,
14-15-16
,
2-3
,
17
. Да, фрагмент
2-3
оттранслирован три раза: сам по себе и в составе других блоков.