2. Исполнительный механизм находит класс, содержащий "главную" точку входа "main", с которой должно начинаться выполнение приложения. Таковым является класс с сигнатурой функции, соответствующей виду static void Main. В случае обнаружения типа с такой сигнатурой происходит загрузка класса и производится попытка выполнения "главной" процедуры (шаги 3 и 4).
3. Загружается класс. Информация о классе загружается и верифицируется с той целью, чтобы убедиться в корректности и согласованности определения класса. Все методы (то есть точки входа исполняемого кода) класса обозначаются как "некомпилированные".
4. Исполнительный механизм пытается выполнить указанную процедуру. Если уже имеется откомпилированный код, связанный с процедурой, осуществляется выполнение этого кода.
5. Если исполнительный механизм обнаруживает, что свойство или метод, которые требуется запустить на выполнение, не откомпилированы, они компилируются по требованию. Производится загрузка содержащейся в классе информации, которая необходима методу. Код верифицируется для гарантии того, что он содержит безопасные, допустимые и корректно сформированные IL-инструкции, а затем подвергается JIT-компиляции. Если метод ссылается на другие типы, которые еще не были загружены, осуществляется необходимая загрузка определений соответствующих классов и типов. Методы, содержащиеся в классах, не компилируются до тех пор, пока в этом не возникнет необходимости; именно в этом и состоит смысл JIT-компиляции.
6. Выполняется скомпилированный к этому моменту метод. Если возникает необходимость в распределении памяти для типов или методов, исполнительному механизму направляются соответствующие запросы. Любые вызовы классов методами возвращают нас к шагу 5.
На первый взгляд, вышеперечисленные действия требуют выполнения большого объема работы, однако в действительности все происходит очень быстро.