Jaotc 는 JDK 9 ~ JDK 16 에 포함된 JDK AOT 컴파일러이다.
JEP 295 에서 제안되었으며 JEP 410 에서 사라졌다.
jaotc --output jaotcResult.so jaotcSource.class
와 같이 미리 AOT 컴파일러로 so 파일을 만들고,
java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./jaotcResult.so HelloWorld.class
와 같이 실행할 수 있다.
하지만 JEP 295 에도 적혀 있듯, 아무도 쓰지도 않고 사용 자체도 어려워서 JDK 에서 빠지게 되었다. 그래서 굳이 jaotc 를 공부할 필요는 없다.
대신 jaotc 는 내부적으로 Graal Compiler 를 사용했으며, jaotc 는 JDK 16 에서 빠지고 난 후 Graal 프로젝트로 편입되었다.
따라서 이제는 GraalVM 을 알아봐야 한다.
Graal VM 은 다음과 같은 기능들을 내걸고 있다.
이러한 기능들이 가능한 근본은 Graal Compiler 때문이다.
GraalVM 은 HotSpot 을 기반으로 만들어진 일종의 JVM 이다.
C2 컴파일러 대신 Graal Compiler 가 동작한다.
GraalVM 은 HotSpot 처럼 일반적인 java 파일을 실행할 수 있으며,
Native Image 생성시에도 사용될 수 있다.
그랄 컴파일러는 처음에는 HotSpot 의 C2 를 대체하기 위한 컴파일러였다.
여기에 다른 몇가지 요구사항들이 합쳐지면서 위의 기능을 모두 제공해주는 GraalVM 의 근본이 되었다.
몇가지 중요한 특징을 알아보자
C++ 로 짜여진 C2 컴파일러에 반해, 그랄 컴파일러는 JEP-243 의 JVMCI 덕분에 자바로 작성될 수 있었다.
언어 독립성이란 말 그대로다. JS 를 GraalVM 에서 실행시킬 수 있다는 것이다.
하지만 중요한 것은 JS 의 특성 및 최적화는 적용되어야 한다.
Graal Compiler 개발진은 애초부터 여러 언어를 지원할 수 있는 컴파일러를 만들고 싶어 했다.
한편 생각해보면 JS 를 Java Class File 로 변환하는 컴파일러를 만들면 되지 않는가? 모든 언어를 Java Class File 로 만드는 컴파일러를 만들면 이미 C2 는 언어 독립적인 컴파일러 같기도 하다.
하지만 그렇지 않다. Java Class File 은 이미 스택 구조, 메서드 호출 규약(invokevirtual) 등 이미 자바에 맞춰진 파일이다.
JS 를 Java Class File 로 바꾼다면 JS 의 동적인 특성은 모두 사라지고 없을 것이다.
그렇다면 어떻게 모든 언어를 대상으로한 독립성을 지킬 수 있을까.
모든 언어는 다르게 생겼지만 하고자 하는 것은 같다. 하드웨어를 동작시켜서 원하는 동작을 하기 위해 언어를 작성하는 것이다. 즉, 실행 흐름 은 모든 언어에서 같을 것이다.
Graal Compiler 는 실행 흐름을 컴파일한다.
실행 흐름을 나타내는 Graph 라는 Graal IR 을 네이티브 코드로 변환한다. 이 방식으로 언어의 독립성을 실현했다.
비교하자면
C2 Compiler 는 Java Class File 을 네이티브 코드로 컴파일하지만,
Graal Compiler 는 Graph(Graal IR) 을 네이티브 코드로 컴파일한다.
가장 먼저 GraalVM 을 설치해야 한다.
Mac 에서 가장 쉽게 GraalVM 을 사용하는 방법은 SDKMAN 을 사용하는 것이다.
https://www.graalvm.org/latest/getting-started/macos/#sdkman

GraalVM 은 여러가지 방법으로 Native Image 를 만들 수 있다.
클래스, jar, java-module 을 gradle, maven, cli tool 을 사용하여 네이티브 이미지를 만들 수 있다.
이번에는 간단하게 native-image cli tool 을 써볼 예정이다.
native-image cli tool 은 GraalVM 내부에서 제공하는 툴로써, GraalVM 과 내부의 Graal Compiler 를 사용하여 자바 코드를 Native Image 파일로 생성할 수 있다.
Polyglot 을 이용하면 타 언어도 가능
native image 에는 사전 컴파일된(AOT) 네이티브 코드와 해당 네이티브 코드를 JVM 없이 실행할 수 있는 런타임(Substrate VM) 이 포함되어 있다.
https://www.graalvm.org/latest/reference-manual/native-image/#from-a-class
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
javac HelloWorld.java
native-image HelloWorld

./helloworld


https://giljae.medium.com/graalvm-%EC%86%8C%EA%B0%9C-84ac547f8df2
GraalVM 을 이용하면 JS 코드를 Java 에서 사용할 수 있다.
또는 JS 파일에 작성된 함수를 Java 에서 불러와 실행할 수 있다.
JS 뿐만 아니라 C, C++, Ruby, Python 등등 많은 언어가 가능하다.
이를 Polyglot 이라 한다.
Truffle 은 언어를 만드는 프레임워크다.
언어를 만든다는건 사실 언어를 기계어로 바꾸는 인터프리터를 만드는 것이다.
Truffle 프레임워크로 만든 애플리케이션은 JS, Python, R 또는 커스텀한 언어를 AST 로 만드는 AST 인터프리터다. AST 는 원래 언어(JS, Python ..) 의 실행 흐름을 담고 있는 자바 객체 트리로서, JVM 에서 실행하면 원래 언어의 코드가 실행되는 것이다.
JS는 HotSpot JVM에서 실행된다.
다만 HotSpot이 JS를 직접 이해해서 실행하는 게 아니라,
Truffle로 구현된 JS 인터프리터(자바 코드)를 실행함으로써 실행된다.
Truffle 프레임워크로 만들어진 인터프리터가 변환한 AST 는 자바 객체이기 때문에 GraalVM 이 아니더라도 HotSpot 에서도 실행될 수 있다.
하지만 Graal Compiler 를 만났을 때 가장 높은 수준의 최적화가 이뤄질 수 있다. 다음 표를 보자.

https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support
// 우리 코드에서 사용할 polyglot api.
// Truffle 프레임워크를 의존성으로 따라 가져온다.
// Truffle 프레임워크는 정의된 언어 컨텍스트의 구현체로 요청을 디스패치하여 해석한 후 Graph 를 만든다
implementation("org.graalvm.polyglot:polyglot:25.0.2")
// JS 폴리글랏 구현체. Truffle 에서 정의한 인터페이스에 맞게 구현되어 있으며, JS 문법을 Truffle 인터페이스로 바인딩한다고 볼 수 있다.
// 예를 들면 JS 를 해석하여 Truffle 인터페이스 A 로 바인딩하는 식.
implementation("org.graalvm.polyglot:js:25.0.2")
2-1. java 파일에서 js 코드 실행하기
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
public class JsFunctionCallDemo {
public static void main(String[] args) {
try (Context ctx = Context.newBuilder("js").build()) {
ctx.eval("js", """
function add(a, b) { return a + b; }
"""); // js code
Value bindings = ctx.getBindings("js");
Value add = bindings.getMember("add");
int res = add.execute(1, 2).asInt();
System.out.println(res); // 3
}
}
}

2-2. java 에서 js 파일 읽어서 실행하기
js file
// Hello.js
// gradle 프로젝트 최상위에 위치시키기
function add(a, b) {
return a + b;
}
java file
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import java.io.File;
public class JsFileCallDemo {
public static void main(String[] args) throws Exception {
File jsFile = new File("hello.js");
try (Context ctx = Context.newBuilder("js").build()) {
Source src = Source.newBuilder("js", jsFile).build();
ctx.eval(src);
Value bindings = ctx.getBindings("js");
Value add = bindings.getMember("add");
int res = add.execute(10, 32).asInt();
System.out.println(res); // 42
}
}
}
https://www.graalvm.org/latest/reference-manual/native-image/guides/build-native-shared-library/
Galahad 는 GraalVM 기술이 JDK 에 포함되도록 하는 프로젝트이다.