인터프리터와 컴파일러
자바스크립트 엔진이란 자바스크립트 코드를 실행하는 프로그램, 인터프리터, 컴파일러를 의미한다.
자바스크립트 엔진은 인터프리터 일수도 있고 JIT 컴파일러를 사용할 수도 있는데 먼저 인터프리터와 컴파일러의 차이를 알아야 한다.
인터프리터 | 컴파일러 |
한 줄 씩 번역한 후 실행한다. | 전체를 번역 한 뒤 실행한다. |
인터프리터의 경우 컴파일 과정이 없고 한 줄 씩 번역해서 실행하기 때문에 실행 속도가 빠르다.
컴파일러의 경우 컴파일 과정이 존재하기 때문에 인터프리터에 비해서 실행 속도가 느리지만 전체에 대해서 미리 번역하기 때문에 중복을 줄일 수 있다.
같은 결과를 반환하는 함수를 10번 실행한다고 해보자.
인터프리터는 함수를 실행할 때마다 함수를 번역한 뒤 실행하기 때문에 불필요한 과정이 포함된다.
그에 비해 컴파일러는 중간에 최적화(Optimization) 과정이 있는데 여기서 불필요한 코드 제거 및 반복 최적화와 같은 과정을 수행한다.
컴파일러를 통해 코드를 번역하면 함수의 결과를 재사용하기 때문에 인터프리터에 비하면 불필요한 연산이 줄어들게 된다.
JIT 컴파일러
JIT 컴파일 방식은 interpret 방식과 compile 방식을 혼합해서 사용하는 방식이다.
실행하는 시점에 interpret 방식으로 기계어 코드를 생성하고 코드를 캐싱하기 때문에 같은 함수가 여러 번 호출되더라도 같은 기계어 코드를 생성하지 않는다.
구체적으로 알아보자.
바이트코드 컴파일러가 소스 코드를 소스 코드와 기계어의 중간 언어인 바이트 코드로 컴파일한다.
코드가 실행되는 시점에 JIT 컴파일러는 바이트 코드를 읽어서 기계어로 변환한다.
코드가 실행되는 시점에 기계어로 변환되기 때문에 JIT(Just In Time)이라고 한다.
이렇게 기계어로 변환된 코드는 캐싱되기 때문에 재사용할 때마다 기계어로 변환할 필요가 없어진다.
즉 전체 코드가 모두 변환되는게 아니라 필요한 부분만 변환하기 때문에 효율적이다.
V8 엔진이 어떻게 JIT 컴파일 방식을 사용하여 속도를 빠르게 할 수 있는지 알아보자.
자바스크립트 V8 엔진
V8 엔진은 내부적으로 interpret 방식과 compile 방식을 함께 사용한다.
Parser
컴파일러가 소스 코드를 기계어로 번역할 때 구문 분석(Syntax Analysis)이라는 과정을 거친다.
구문 분석 과정에서 소스 코드는 Tokenizer -> Lexer -> Parser를 거치면서 기계어로 변환된다.
Tokenizer를 거치면서 구문을 의미있는 단위로 나누어 토큰화를 진행한다.
예를 들어 "I am a boy"라는 문장을 의미 있는 단위로 나눈다면 [ "I", "am", "a", "boy" ]가 될 것이다.
토큰의 종류는 다음과 같은 구조로 이루어져 있다.
어휘소 | 토큰 분류 |
sum | Identifier |
= | Assignment operator |
3 | Integer literal |
+ | Addition operator |
2 | Integer literal |
; | End of statement |
Tokenizer를 통해 구분을 의미 있는 단위로 쪼갰다면 토큰들의 의미를 분석하는 과정을 거친다.
어떠한 구문이 무슨 역할을 하는지 의미를 분석한다.
Tokenizer + Lexer의 과정을 Lexical Analyze라고 한다.
이제 Parser를 통해 데이터를 구조적으로 나타낼 수 있다.
Parser의 결과물은 보통 AST(Abstract Syntax Tree) 형태로 생성된다.
아래의 코드를 AST로 나타내면 다음과 같다.
while b ≠ 0
if a > b
a := a − b
else
b := b − a
return a
이렇게 Parser를 거쳐 생성된 AST는 Ignition Interpreter에게 넘어간다.
Ignition의 컴파일러는 AST를 바이트 코드로 컴파일한 후 Ignition의 interpreter가 바이트 코드를 한 줄씩 실행한다.
바이트 코드는 기계어로 가기 전 단계의 코드라고 볼 수 있으며 어셈블리어와 유사하다.
Ignition에 의해 컴파일된 바이트 코드는 Turbofan에서 최적화 된다.
Turbofan에서 중복 코드를 재사용하면서 코드를 줄이고 속도가 빨라졌다.
출처
https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775
https://artistdata.tistory.com/13
https://ko.wikipedia.org/wiki/JIT_%EC%BB%B4%ED%8C%8C%EC%9D%BC
댓글