Young Da Code 👨💻
Первый командный дайджест о мобильной разработке 🍕
Post #131
225
🤓 🚀 Compile vs Runtime. Начало
Мы часто пишем код так, будто машинка за кадром просто «выполняет инструкции», но в реальности путь от исходника до выполнения куда длиннее и интереснее.
Сегодня попробуем пройти его последовательно: от compile time и LLVM IR до Swift runtime, Obj-C runtime и механизмов диспетчеризации методов.
🧩 Compile Time vs Runtime:
Swift — язык, который сознательно переносит максимум работы на этап компиляции.
Чем больше информации компилятор узнает о типах, generics, наследовании, тем меньше остаётся неопределённости в рантайме, и тем быстрее будет работать ваш код.
Compile Time — что делает компилятор Swift:
- проверяет типы и связи между ними
- анализирует возможности оптимизации
- генерирует LLVM IR — промежуточное представление программы
- формирует метаданные типов и служебные таблицы, необходимые рантайму
решает, можно ли:
- специализировать generics в конкретный код
- де-виртуализировать вызовы
- развернуть протокол в статический вызов
- Если типы известны заранее — компилятор построит прямой статический вызов без участия runtime.
Runtime — что происходит «вживую»:
- выделяется память под объекты
- работает ARC
- инициализируются метаданные типов
- происходит lookup таблиц: vtable, witness table
- выполняется упаковка/распаковка типов в existential container
- работает Obj-C runtime
- вызываются методы — статические, виртуальные или динамические
🟣 Obj-C Runtime — всё объект, всё сообщение:
Чтобы оценить, насколько иначе работает Swift, сначала вспомним принцип Obj-C.
Объект в Obj-C — это структура, в которой есть поле isa:
Классы в objc одновременно и классы и обьекты.
Вызов метода в objc:
на самом деле является:
вызовом функции
, которая:
- читает obj->isa
- ищет селектор в кеше
- поднимается по иерархии классов (если не находит метод — запускает цепочку message forwarding)
- и только после всех попыток бросает unrecognized selector
🔵 Swift Runtime — другой мир:
Swift не опирается на Obj-C runtime (кроме совместимого кода) и имеет собственную модель исполнения.
Swift-структуры и enum:
- xранятся inline (на стеке или внутри других структур)
- не имеют isa
- становятся heap-объектами только при боксинге
Swift-классы:
- всегда heap-объекты
- имеют header, содержащий указатель на Swift type metadata
- если совместимы с Obj-C — получают и поле isa
То есть:
У value types нет Obj-C-объектности. У reference types есть типовая информация, но она не идентична Obj-C-isa — Swift организует её иначе.
🧬 LLVM IR — слой, где принимаются ключевые решения:
Swift не компилируется напрямую в машинный код — сначала он становится LLVM IR.
Это низкоуровневое, но типобезопасное представление, в котором компилятор:
- специализует generics (когда возможно)
- удаляет виртуальность
- inline-ит функции
- оптимизирует вызовы протоколов
- устраняет лишние копирования
- уменьшает динамику
⚙️ Именно на IR-уровне решается, каким будет вызов метода:
Static dispatch
- метод у struct/enum/extension
- метод final
- функция свободная
- generics-функция после специализации
Witness dispatch
Вызов через протокол, когда тип известен, но вызов идёт «через протокол».
Компилятор кладёт указатели методов в witness table, и вызов выполняется через неё.
Virtual dispatch
Если метод может быть переопределён — он попадает в таблицу виртуальных методов.
Если нельзя — становится статическим вызовом.
Dynamic Dispatch (Obj-C) Когда Swift-код:
- наследует NSObject
- помечен @objc
- помечен dynamic
Вызов идёт через objc_msgSend.
📎 Swift Runtime
#L #SwiftRuntime #MetodDispatch
👏
Мы часто пишем код так, будто машинка за кадром просто «выполняет инструкции», но в реальности путь от исходника до выполнения куда длиннее и интереснее.
Сегодня попробуем пройти его последовательно: от compile time и LLVM IR до Swift runtime, Obj-C runtime и механизмов диспетчеризации методов.
🧩 Compile Time vs Runtime:
Swift — язык, который сознательно переносит максимум работы на этап компиляции.
Чем больше информации компилятор узнает о типах, generics, наследовании, тем меньше остаётся неопределённости в рантайме, и тем быстрее будет работать ваш код.
Compile Time — что делает компилятор Swift:
- проверяет типы и связи между ними
- анализирует возможности оптимизации
- генерирует LLVM IR — промежуточное представление программы
- формирует метаданные типов и служебные таблицы, необходимые рантайму
решает, можно ли:
- специализировать generics в конкретный код
- де-виртуализировать вызовы
- развернуть протокол в статический вызов
- Если типы известны заранее — компилятор построит прямой статический вызов без участия runtime.
Runtime — что происходит «вживую»:
- выделяется память под объекты
- работает ARC
- инициализируются метаданные типов
- происходит lookup таблиц: vtable, witness table
- выполняется упаковка/распаковка типов в existential container
- работает Obj-C runtime
- вызываются методы — статические, виртуальные или динамические
Compile time строит все дороги и развязки. Runtime по ним едет.
🟣 Obj-C Runtime — всё объект, всё сообщение:
Чтобы оценить, насколько иначе работает Swift, сначала вспомним принцип Obj-C.
Объект в Obj-C — это структура, в которой есть поле isa:
struct objc_object {
Class isa;
};
Классы в objc одновременно и классы и обьекты.
Вызов метода в objc:
[obj doSomething];
на самом деле является:
вызовом функции
objc_msgSend(obj, @selector(doSomething))
, которая:
- читает obj->isa
- ищет селектор в кеше
- поднимается по иерархии классов (если не находит метод — запускает цепочку message forwarding)
- и только после всех попыток бросает unrecognized selector
Да, Objective-C — это надстройка над языком C, которая добавляет к нему объектно-ориентированную парадигму (ООП) и динамические возможности через систему сообщений и объекты, сохраняя при этом полную совместимость с кодом на чистом C, что позволяет использовать их совместно
🔵 Swift Runtime — другой мир:
Swift не опирается на Obj-C runtime (кроме совместимого кода) и имеет собственную модель исполнения.
Swift-структуры и enum:
- xранятся inline (на стеке или внутри других структур)
- не имеют isa
- становятся heap-объектами только при боксинге
Swift-классы:
- всегда heap-объекты
- имеют header, содержащий указатель на Swift type metadata
- если совместимы с Obj-C — получают и поле isa
То есть:
У value types нет Obj-C-объектности. У reference types есть типовая информация, но она не идентична Obj-C-isa — Swift организует её иначе.
🧬 LLVM IR — слой, где принимаются ключевые решения:
Swift не компилируется напрямую в машинный код — сначала он становится LLVM IR.
Это низкоуровневое, но типобезопасное представление, в котором компилятор:
- специализует generics (когда возможно)
- удаляет виртуальность
- inline-ит функции
- оптимизирует вызовы протоколов
- устраняет лишние копирования
- уменьшает динамику
⚙️ Именно на IR-уровне решается, каким будет вызов метода:
Static dispatch
- метод у struct/enum/extension
- метод final
- функция свободная
- generics-функция после специализации
Witness dispatch
Вызов через протокол, когда тип известен, но вызов идёт «через протокол».
Компилятор кладёт указатели методов в witness table, и вызов выполняется через неё.
Virtual dispatch
Если метод может быть переопределён — он попадает в таблицу виртуальных методов.
Если нельзя — становится статическим вызовом.
Dynamic Dispatch (Obj-C) Когда Swift-код:
- наследует NSObject
- помечен @objc
- помечен dynamic
Вызов идёт через objc_msgSend.
📎 Swift Runtime
#L #SwiftRuntime #MetodDispatch
👏
- ❤ 4
- 💩 2








