본문 바로가기
ios/swift

final 키워드에 따른 vtable 차이

by kimyounggyun 2024. 5. 11.

상속 가능한 클래스는 메서드 오버라이딩이 가능한데요. 스위프트는 런타임에 vtable(virtual method table)을 참고해 어떤 메서드를 호출할지 결정합니다. 스위프트 OptimizationTips 문서에 따르면 런타임 성능을 올리는 방법 중 하나는 클래스 혹은 메서드에 final 키워드를 붙여 동적 디스패치(런타임 메서드 바인딩)를 줄이는 것이라고 합니다. 소스 코드를 raw SIL로 변환해 final 키워드에 따라 vtable의 차이를 눈으로 보려고 합니다.

SIL in the Swift Compiler

At a high level, the Swift compiler follows a strict pipeline architecture.

스위프트의 빌드 과정 중 컴파일 단계에서는 엄격한 절차가 있습니다.

Syntax analysis

The Parse module constructs an AST from Swift source code.

Parse 모듈은 소스 코드를 구문 분석하여 구문 트리(AST)를 생성하는데요. 이 과정에서 스위프트 문법 규칙을 적용하고 구문 오류를 검출합니다.

Semantic analysis

The Sema module type-checks the AST and annotates it with type information.

Sema 모듈은 AST를 이용하여 소스 코드가 스위프트 언어 정의에 의미적으로 부합하는지 검사합니다. 이 단계에서 타입 검사가 이루어집니다.
타입 검사 규칙은 docs/TypeChecker.md에서 확인할 수 있습니다.

Generate raw SIL

The SILGen module generates raw SIL from an AST.

SILGen 모듈은 AST로부터 Raw SIL을 만듭니다. SIL은 Swift Intermediate Language인데요. SIL은 우리가 작성한 스위프드 코드와 LLVM 컴파일러가 이해할 수 있는 중간 표현 코드인 LLVM IR 사이의 중간 표현 코드입니다.

Generate Canonical SIL

A series of Guaranteed Optimization Passes and Diagnostic Passes are run over the raw SIL both to perform optimizations and to emit language-specific diagnostics. These are always run, even at -Onone, and produce canonical SIL.

General SIL Optimization Passes optionally run over the canonical SIL to improve performance of the resulting executable. These are enabled and controlled by the optimization level and are not run at -Onone.

SILOptimizer은 raw SIL을 Optimization level에 따라 최적화하여 canonical SIL로 만듭니다. 이때 Optimizaion level에 상관없이 No Optimization에서도 실행되는 무조건 실행되는 최적화 과정이 있는데요. 기본적인 최적화 이후에 Optimization level에 따라 추가적으로 최적화를 합니다.
관련 문서는 docs/OptimizerDesign.md에 있습니다.

LLVM IR

IRGen lowers canonical SIL to LLVM IR.

The LLVM backend (optionally) applies LLVM optimizations, runs the LLVM code generator and emits binary code.

IRGen 모듈이 canonical SIL을 LLVM IR으로 만듭니다.

Raw SIL과 vtable

간단한 클래스를 하나 만듭니다.

아래 명령어를 통해 raw SIL을 만들 수 있는데요. 터미널에 출력된 내용을 파일로 만들어봅니다.

$ swiftc -emit-silgen Vehicle.swift > Vehicle.sil

swift-demangle을 통해 이름을 알아보기 쉽게 바꿀 수도 있습니다. 사실 vtable만 볼 것이라 demagle은 필요 없습니다.

$ swiftc -emit-silgen Vehicle.swift | xcrun swift-demangle > Vehicle.sil

raw SIL을 보면 아래에 vtable정보가 있습니다. 자동으로 생성된 소멸자, 프로퍼티의 getter와 setter가 메서드로 추가된 것을 확인할 수 있습니다.

클래스에 final 키워드를 붙이니 vtable이 바뀌었는데요. 일부 메서드가 vtable에서 사라진 모습을 확인할 수 있습니다. final 키워드로 인해 오버라이딩이 불가능해 더 이상 동적 디스패치가 필요 없기 때문입니다.

 

출처

댓글