The Java Virtual Machine & the Kotlin Compiler
The Java Virtual Machine & the Kotlin Compiler
The Java
Virtual Machine
& the Kotlin
Compiler
@kotlin | Developed by JetBrains
The Java language
● Has a garbage collector, meaning you can allocate memory and it will be freed
automatically.
Compilation process – Java vs C
Java bytecode
public class examples/Main {
public <init>()V
L0
LINENUMBER 3 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lorg/examples/Main; L0 L1 0
public class Main {
MAXSTACK = 1
public static void main(String[] args) { MAXLOCALS = 1
System.out.print("Hello, World!");
} public static main([Ljava/lang/String;)V
} L0
LINENUMBER 5 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "Hello, World!"
ICONST_0
ANEWARRAY java/lang/Object
INVOKEVIRTUAL java/io/PrintStream.print
(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
POP
L1
LINENUMBER 6 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
MAXSTACK = 3
MAXLOCALS = 1
}
The JVM under the hood
JVM
Class loading
services Interpreter
JIT-compiler
lifetime
Generations
● Young
● Old
Stack
A D
C
B E
Serial garbage collector
The first garbage collector created was the serial garbage collector, which is single-threaded, and the
parallel and CMS garbage collectors are based on it.
Eden S0 S1 Tenured
How garbage collection works
Current state:
Before GC:
Surviving objects
After GC:
How garbage collection works
Current state:
Before GC:
After GC:
How garbage collection works
Current state:
Before GC:
After GC:
How garbage collection works
Current state:
Before GC:
After GC:
● Pieces of code are compiled for a specific platform to optimize the execution time.
Interpreter JIT-compiler
● Starts working almost instantly. ● Kicks in after a long delay (needs time
Code that will take a long time to run or code that runs frequently, because the
compilation overhead will be covered by the profit from having optimized execution.
Just-in-time compilation
JVM
Class loading
services Interpreter
JIT-compiler
class PiUtils {
private static final double PI = 3.141592653589;
class PiUtils {
private static final double PI = 4;
Reflection
● Provides the ability to integrate into the compilation process (compiler plugins).
.kt files
Kotlin compiler
Parser
Lexer PSI or Lighter AST builder
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
Su CST Su AST
m m
left operand right operand
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
FUN
'String'
Kotlin compiler: PSI
fun hello(user: String) = println("Hello, $user")
CALL_EXPRESSION
VALUE_ARGUMENT_LIS
REFERENCE_EXPRESSION
T
VALUE_ARGUMEN
'println' '(' ')'
T
STRING_TEMPLATE
SHORT_STRING_TEMPLATE_ENT
'\"' LITERAL_STRING_TEMPLATE_ENTRY '\"'
RY
'user'
Kotlin compiler: PSI
fun hello(user: String) = println("Hello, $user")
CALL_EXPRESSION
VALUE_ARGUMENT_LIS
REFERENCE_EXPRESSION
T
VALUE_ARGUMEN
'println' '(' ')'
T
STRING_TEMPLATE
SHORT_STRING_TEMPLATE_ENT
'\"' LITERAL_STRING_TEMPLATE_ENTRY '\"'
RY
'user'
Kotlin compiler: PSI
fun hello(user: String) = println("Hello, $user")
CALL_EXPRESSION
VALUE_ARGUMENT_LIS
REFERENCE_EXPRESSION
T
VALUE_ARGUMEN
'println' '(' ')'
T
STRING_TEMPLATE
SHORT_STRING_TEMPLATE_ENT
'\"' LITERAL_STRING_TEMPLATE_ENTRY '\"'
RY
'user'
Kotlin compiler
Parser
Lexer PSI or Lighter AST builder
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
returnTypeRef
ResolvedTypeRef(=kotlin/String)
FIR? Another tree!
fun hello(user: String) = println("Hello, $user")
returnTypeRef
ResolvedTypeRef(=kotlin/String)
FIR? Another tree!
fun hello(user: String) = println("Hello, $user")
StringConcatenationCall
argumentList typeRef
arguments arguments
calleeReference typeRef
StringConcatenationCall
argumentList typeRef
arguments arguments
calleeReference typeRef
StringConcatenationCall
argumentList typeRef
arguments arguments
calleeReference typeRef
StringConcatenationCall
argumentList typeRef
arguments arguments
calleeReference typeRef
if (b) { when {
println("Hello") b -> println("Hello")
}
}
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
} }
Library A Library B
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
valueParameters
returnTypeRef ValueParameter (name = user) ConstExpression (value = "Hello, ", kind = String)
returnTypeRef typeRef
Type Type
inference resolution
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler: control- and data-flow
analysis
interface A {
Enter function bar
}
Jump: break
Kotlin compiler
Parser
Lexer PSI or Lighter AST builder
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
On the backend, we
DO NOT resolve, Other
JVM JavaScript Native
but only use the (WASM, Python,
received information etc.?)
Kotlin compiler
Parser
Lexer PSI or Lighter AST builder
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
platforms.
Kotlin compiler: resolved tree
Type: kotlin.String
Type: kotlin.String
Type: kotlin.Unit
Call: kotlin.io.println(kotlin.String)
package helloWorld
FUN name:hello visibility:public modality:FINAL <>(user:kotlin.String) FUN name:main visibility:public modality: FINAL <>(args:kotlin.Array<kotlin.String>)
returnType:kotlin.Unit returnType:kotlin.Unit
BLOCK_BOD BLOCK_BOD
VALUE_PARAMETER name:user index:0 type:kotlin.String VALUE_PARAMETER name:args index:0 type:kotlin.Array<kotlin.String>
Y Y
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit CALL 'public final fun get (index: kotlin.Int): T of kotlin.Array CALL 'public final fun hello (user: kotlin.String): kotlin.Unit declared
[inline] declared in kotlin.io.ConsoleKt' [operator] declared in kotlin.Array' in helloworld'
type=kotlin.Unit origin=null type kotlin.String origin=null type kotlin.Unit origin=null
message: index:
$this: user:
STRING_CONCATENATION type=kotlin.String
CONST Int type=kotlin.Int value=0
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
RETURN type=kotlin.Nothing
from='public final fun hello (user: kotlin.String): kotlin.Unit declared in helloworld'
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in
kotlin.io.ConsoleKt' type=kotlin.Unit origin=null
message:
STRING_CONCATENATION type=kotlin.String
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
Platform-specific code,
such as bytecode for the Other
JVM JavaScript Native
JVM (WASM, Python,
etc.?)
Kotlin compiler
Parser
Lexer PSI or Lighter AST builder
.kt files
Frontend
Resolutio
Diagnostics Type inference
n
Backend
IR generator IR optimizer
Platform-specific code,
such as bytecode for the Other
JVM JavaScript Native
JVM (WASM, Python,
etc.?)
KLibs
JAR analogues – store a serialized IR for the subsequent use of cross-platform libraries.
JVM code
Kotlin/JVM Classes
Native
Kotlin/Native
objects
Native code
Compiler plugins
You can extend any compile phase via compiler plugins. To do so, you need to implement
compiler extensions and register them.
Don’t forget to use supportsK2 = true if you need to support the FIR frontend
Compiler plugins: FIR extensions
To get the full list of the extensions, please see: package org.jetbrains.kotlin.fir.extensions (link).
Consider an example:
/*
* Generates top level class
*
* package foo.bar
*
* public final class MyClass {
* fun foo(): String = "Hello world"
*}
*/
Compiler plugins: FIR extensions
You use a special key to mark everything generated by the compiler and can transfer any
information between frontend and backend. So it also helps to find the new declaration to
generate it’s IR.
...
}
Compiler plugins: FIR extensions
}
Compiler plugins: IR extensions
Actually, the compiler has only one extension for IRs: IrGenerationExtension.
You just need to implement some transformers and accept them: