24년도 5월, Kotlin 2.0.0의 릴리즈가 출시되었고 이는 K2컴파일러를 지원한다. 기존 컴파일러의 프론트엔드, 백엔드 그리고 K2에서 제공할 New fronted에 대해 설명한다.
컴파일러는 소스 코드를 낮은 수준의 기계언어로 변환하는 블랙박스이다.
Kotlin의 간단한
if
문은 복잡한 자바 바이트코드의goto
문으로 변경되게 된다.
위 사진에서 코틀린 컴파일러는 Kotlin 코드를 JVM 바이트 코드로 변환한다. 그러나 여기서 JVM 바이트 코드는 낮은 수준의 기계언어가 아니다. (이는 JVM에 의해 이해 기계 언어로 변환된다)
즉 컴파일러의 정의는 타겟 언어로의 변환이라해도 좋다.
코틀린 컴파일러는 자바 바이트코드로만 변환되는 것이 아니다.
등 개발자가 작성한 고급언어를 여러 환경에서 실행될 수 있도록 다양한 형태를 지원한다.
여기서 특이한 점은 JavaScript
는 기계언어가 아닌, 개발자가 직접 작성하는 고급언어으로도의 변환도 지원한다는 것이다.
따라서 코틀린 컴파일러는 JVM, JS 및 네이티브(LLVM)
으로 3가지 플랫폼으로의 변환을 지원한다는 것만 알고 있으면 될 것 같다.
컴파일러라는 블랙박스의 내부를 세분화하는 일반적인 방법은 프론트엔드와 백엔드로 나누는 것이다.
어플리케이션 개발의 프론트와 백엔드와는 다른 의미를 가진다.
대표적인 역할로는 아래와 같이 표현할 수 있다.
컴파일러의 Kotlin 2.0.0이전, 즉 K2컴파일러 이전의 코틀린 컴파일러는 위와 같은 형태로 작성되게 된다.
파서는 소스 코드인 Kotlin 파일그룹을 인풋으로 받으며, 소스 코드의 유효성을 체크하고, 문법이 맞으면 구문트리를 빌드한다.
if (pet is Cat) {
pet.meow()
} else {
println("*")
}
컴파일러는 위와 같은 코틀린 언어를 이해하기보단 그대로 받아쓰기하듯 문법트리로 변환한다.
파서로부터 문법트리를 받아 의미정보를 추가한다.
의미정보란?(Sementic info)
코드에 사용된 함수, 변수, 타입에 대한 모든 세부 정보로, 함수의 출처는 어디인가?, 타입은 무엇인가?에 대한 답변이다.
함수, 변수, 타입에 대한 세부 정보에 대한 답을 찾는다
Semantic analyzer의 컴파일시간의 대부분은 위와 같은 변수에 대한 타입을 추론하는 과정이다.
이는 파서와 달리 -> 파라미터의 개수가 안맞거나, 타입이 맞지않거나, 함수를 참조하지 못하거나 등이면 에러를 발생.
if (pet is Cat) {
pet.meow(1) // Error: Too many arguments
} else {
pet.mmeow() // Error: Unresolved reference
}
프론트엔드는 초기 구조에 구조와 의미를 더하는 것이다. 이 정보를 활용하여 백엔드에서 타겟코드를 생성하도록 한다.
알고있듯이 코틀린 컴파일러는 세가지 타겟 언어를 지원한다. 이에 따라 세가지의 백엔드가 존재한다.
과거 10년전 코틀린 컴파일러는 Syntax tree와 Sementic Info를 통해 JVM, JS코드를 직접 만들어 냈다. (이는 코틀린 개발자가 8명이여서 빠르게 개발하기 위함) 따라서 Intermediate code Generator 즉 (IR : intermediate Representation)은 사용하지 않았다.
하지만, LLVM bitcode generator가 등장하게되며, 일부 로직(겹치는 중간 코드가 많음)을 공유할 수 있는것이 확인되어서 IR을 LLVM에만 도입하게 된다.
IR(Intermediate Representaion)이란?
코드 생성을 위해 설계된 코드의 트리라고 생각하면 편하다.
K2컴파일러에서는 이전 구조에서 추상화의 문제점을 깨닫고 이를 수정하였다.
백엔드에서 타겟언어로의 변환은 복잡하지만 IR을 거쳐 공통 로직을 처리하고 나면 좀 더 간단하게 변환할 수 있다.
이러한 과정을 거치며 내부 클래스가 없어지거나, 특정 함수들이 해쉬값을 통한 함수로 포장되거나... 등등에 따른 타입추론이 좀 더 간단해지는 면이 있어서 코틀린 작성도 도움이 될 것 -> 이후 설명
New Frontend에서의 FIR은 디슈가링(안드로이드에서 호환성을 위해 일컫는 Desugaring이랑은 다름)을 지원한다.
디슈가링이란 복잡한 언어 구문을 단순화하고 더 간단한 구문으로 대체하는 것이다.
전체 인프라, 코드베이스를 갈아엎느라 좀 늦었다. 해당 영상은 21년도에 나왔지만, Kotlin 2.0은 이제서야 (24/05/21)에 릴리즈 되었다.