Develop Note by J.S.

[Javascript] 컴파일 언어, 인터프리터 언어 (with. V8엔진, 웹 어셈블리) 본문

Language/Javascript

[Javascript] 컴파일 언어, 인터프리터 언어 (with. V8엔진, 웹 어셈블리)

js-web 2024. 7. 4. 11:27
반응형

1. 개요

- 프로그래밍 언어는 실행 방법에 따라 컴파일 언어와 인터프리터 언어로 구분할 수 있습니다.

- 컴파일러(Compiler)는 개발자가 작성한 고급언어를 기계가 이해할 수 있는 저급언어로 번역하는 프로그램을 뜻합니다. 

- 어느 시점에 기계어로 번역이 되어 실행되는 지에 따라 컴파일 언어, 인터프리터 언어로 나뉘게 됩니다.

1) 컴파일 언어 (정적 컴파일러)

원시코드(개발자가 작성한 코드)를 컴파일 타임에 모든 소스를 기계어로 변환하여 실행파일로 만들고 컴파일은 단 한번 수행됩니다. 런타임 시점에는 이미 기계어로 변경된 소스코드를 수행할 뿐입니다. 

- 컴파일 언어 : C, C++, C#, JAVA 등

2) 인터프리터 언어

컴파일 언어와 반대로 컴파일 과정없이 런타임에 소스코드를 한줄씩 해석하며 즉시 실행하는 언어로, 컴파일 언어에 비해 속도가 느립니다. 하지만 코드 수정 시 빌드없이 바로 수정사항이 반영되는 장점이 있습니다. 

- 인터프리터 언어 : Javascript, Python, Ruby 등

- 2017년 10회 ACM SIGPLAN 국제 컨퍼런스 논문 자료
- 각 언어로 표현된 10개의 프로그래밍 로직으로 테스트한 결과에 대한 TABLE

언어별 에너시효율성, 시간, 메모리 사용량

 

2. JIT(Just-In-Time) 컴파일러 (동적 컴파일러)

프로그램이 실행되는 시점에 기계어로 번역하는 컴파일 방식입니다. JIT컴파일러는 전체 코드를 한번에 컴파일하지 않고, 실제로 실행되는 코드(바이트코드)를 최적화(컴파일)하여 실행시킵니다. 

중간언어 : 고급언어와 저급언어(기계어) 사이의 언어를 말합니다. 기계어가 수행되는 하드웨어가 아닌 가상머신이라는 소프트웨어서 수행됩니다. 

 

JIT컴파일러는 인터프리터의 특성과 정적 컴파일의 특성을 혼합한 방식입니다. 실행 시점에 인터프리트 방식으로 기계어 코드를 생성하고 그 코드를 캐싱하여 같은 메서드가 여러번 실행될 때 매번 기계어코드를 생성하는 것을 방지합니다. 

Java의 코드 변환 과정

 

따라서 JIT컴파일러는 실행성능이 느린 인터프리터 방식보다는 빠르고, 생산성이 느린 컴파일 방식보다는 동적 환경에서의 대응이 빠릅니다. 하지만 순수 코드의 실행성능 측면에서는 정적 컴파일 방식에 비하여 컴파일 시점의 코드의 최적화 할 시간이 상대적으로 짧기 때문에, 정적 컴파일 방식이 가장 빠릅니다. 

3. V8엔진의 적응형 JIT 컴파일러 (AJITC: Adaptive Just In Time Compiler )

* V8 엔진이 사용하는 특정한 컴파일 방식이 아닌 개념적인 용어로, Javascript Engine에 적응한 JIT 컴파일러를 뜻한다.

 

브라우저에서 동작되는 자바스크립트의 언어 특성은 JITC에서의 효율성이 떨어집니다. 

function sum(a, b) {
	return a + b;
}

예를들어 위와 같이 두개의 파라메터를 받아 덧셈을 하여 리턴하는 함수가 있습니다. 해당 함수를 JIT컴파일러가 받아드린 후 컴파일을 하게되면 각 파라메터의 string, int, float 등의 모든 변수 타입에 대한 네이티브 코드로 최적화 해야하는데, 이는 너무 비효율적이기 때문에 기계어로 컴파일 하지 않고 바이트코드를 그대로 실행하게 됩니다. 

 

이러한 동적특성이 강한 언어 및 환경에서는 실제로 컴파일되는 것보다 인터프리터의 기능만이 동작되기 때문에 JITC사용이 비효율 적일 수 밖에 없습니다.

 

그래서 이러한 브라우저 환경에서의 Javascript 엔진에 적응한 JIT 컴파일방식을 사용하게 됩니다.
현재 V8엔진은 IgnitionTurboFan이라는 두 가지 주요 기능을 사용합니다. Ignition는 빠른 시작을 위한 컴파일러이고, TurboFan은 고급 최적화를 위한 컴파일러입니다. 

동작방식

1. Javascript의 소스코드가 로딩되면 파싱 후 AST로 보냅니다. 

2. AST(추상구문 트리)로 변환된 자바스크립트 코드를 Ignition에서 한줄한줄 읽어들여 바이트코드로 변환시킵니다.

3. 이후 V8엔진은 런타임 과정 중 계속 실행되는 메소드들을 추적하여 Hot Spot(과열지점)을 찾습니다. 

4. 과열된 코드를 TurboFan으로 보내서 최적화 컴파일(기계어)을 실행합니다. 

Javascript 코드가 ByteCode로 변환되는 과정

Ignition은 register machine을 사용합니다. Register machine은 하드웨어에 존재하는 register를 추상화시켜 virtual register를 구현합니다. 따라서 바이트 코드를 기계어로 컴파일하지 않고 Ignition 인터프리터가 한줄씩 읽어들여 코드를 실행 시킬수 있습니다.

 

 

만약 위에 sum() 메소드에 a=1, b=2를 대입한 결과로 3을 얻게 되는 경우, 바이트코드를 즉시 실행하게 되면 몇번이고 호출될 때마다 재 연산 하여 3의 값을 리턴해주게 됩니다. 복잡한 연산식의 경우 효율이 많이 떨어지게 되는데요, 이것을 지속적으로 체크하여 과열시점에 기계어로 컴파일 한다면 최적화된 기계어는 sum() 메소드의 결과값은 '3'이라고 기억하고 있게 됩니다. 

 

따라서 Hot Spot이 빈번하게 발생되는 코드일 수록 최적화 컴파일의 중요도를 더욱 느낄수 있습니다.

 

4. 웹 어셈블리

웹 어셈블리는 2015년에 발표되었으며 메이저(Firefox, Chrome, Safari, Edge 등)한 대부분의 브라우저에서 지원되고 있습니다. 사용방법은 C, C++, Rust, AssemblyScript등의 프로그래밍 언어로 작성된 소스코드를 바이트코드로 컴파일하여 제공됩니다. 브라우저에는 로드시점부터 이미 바이트 코드로 제공되며 바이너리 검증과정 이후 매우 빠르게 기계어로 컴파일됩니다. 이미 최적화된 형태로 제공되기 때문에 엄청 빠른 컴파일 속도를 제공합니다. 

 

WebAssembly를 활용한 제품

 

따라서 기존의 자바스크립트보다 빠른 로딩속도, 빠른 실행 속도, 메모리관리의 유리함 등의 장점이 있고 애니메이션, 게임 및 복잡한 알고리즘 연산에 이상적이라는 장점이 있습니다. 하지만 DOM조작 및 이벤트 처리와 같은 웹 개발 작업에는 자바스크립트가 적합하기 때문에 필요시 선택적으로 사용할 수 있습니다. 

 

예시 

C 소스코드

#include <stdio.h>

int factorial(int n) {
  if (n == 0)
    return 1;
  else
    return n * factorial(n-1);
}

 

WebAssembly IR(최적화된 중간코드)

get_local 0
i64.eqz
if (result i64)
    i64.const 1
else
    get_local 0
    get_local 0
    i64.const 1
    i64.sub
    call 0
    i64.mul
end

 

.WASM (Binary)

20 00
50
04 7E
42 01
05
20 00
20 00
42 01
7D
10 00
7E
0B

 

 

 

 

 

 

참고 사이트

https://spaghetti-code.tistory.com/35

https://ko.wikipedia.org/wiki/JIT_%EC%BB%B4%ED%8C%8C%EC%9D%BC

https://mangkyu.tistory.com/301

https://velog.io/@kich555/JIT-Compiler-Chrome-V8-Engine

https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC#cite_note-Launch_bug-19

https://medium.com/@devjohnpark/v8-engine-deep-dive-ad664bc4ab43

반응형

'Language > Javascript' 카테고리의 다른 글

[Javascript] Function Pipeline  (0) 2024.08.29
[Javascript] Promise의 중단 처리 (AbortSignal)  (0) 2024.01.09
[Javascript] Event Loop, Task Queue  (0) 2023.09.18
[Javascript] Prototype  (0) 2023.06.29
[Javascript] This  (0) 2023.06.28