자바스크립트: 인터프리터 언어인가, 컴파일러 언어인가?
컴퓨터 언어는 크게 인터프리터 언어와 컴파일러 언어 두 가지로 나뉠 수 있다.
- 인터프리터 언어: 소스 코드를 한 줄씩 해석하고 실행하는 방식
- 코드가 실행될 때마다 해석되기 때문에 실행 시간이 비교적 길 수 있다. 그러나 인터프리터 언어의 장점은 개발과 디버깅이 빠르다는 것이다. 코드의 한 부분이 변경되면 전체를 다시 컴파일 할 필요가 없으므로 개발 시간을 절약할 수 있다.
- Python, Ruby 등
- 컴파일러 언어: 소스 코드를 기계어로 변환하는 컴파일 과정을 거치는 방식
- 변환된 코드는 CPU가 직접 실행할 수 있다. 컴파일 과정을 거치면 실행 속도가 빠르지만, 변경사항이 생길 때마다 다시 컴파일해야 하는 불편함과 디버깅 또한 인터프리터 언어에 비해 복잡할 수 있다.
- C, C++, Java 등
인터프리터 언어는 실행 시간이 길지만 개발 및 디버깅이 빠르며, 컴파일러 언어는 실행 속도가 빠르지만 컴파일 과정이 필요하고 디버깅이 복잡할 수 있다.
기본적으로 자바스크립트는 인터프리터 언어에 해당한다. 다른 대표적인 컴파일러 언어인 C언어 혹은 C++의 경우에는 컴파일 과정(+어셈블러 +링커) 을 통해 실행파일을 생성해주어야 비로소 프로그램 실행이 가능해진다.
반면 자바스크립트 같은 언어의 경우에는 위의 사진처럼 코드 한줄씩만 입력하더라도 바로바로 실행하며 결과를 확인하는 것이 가능하기에 인터프리터 언어에 해당하게 된다. 이는 자바스크립트가 만들어질 당시 웹문서 구조를 동적으로 나타내기 위해 제작된 언어이기에 가벼운 인터프리터 구조가 적합했기 때문이다.
그렇다고 자바스크립트가 따로 별도의 과정없이 바로 컴퓨터가 실행가능한 것은 아니다. 자바스크립트가 인터프리터에 전해지기 일련의 과정을 거쳐야 한다.
자바스크립트 뿐만 아니라 모든 고급언어들은 컴퓨터에서 구동되기 위해서 기본적으로 기계가 이해가능한 기계어로 변환되어질 필요가 있다.
위에서 보다시피 자바스크립트는 기계에게 전달되기전에 바이트 코드로 변환되고 이를 받아 가상머신에 의해 기계어로 변환된다. 이러한 일련의 변환 과정은 아래와 같이 진행된다.
1) 바이트 코드로의 변환
자바스크립트 엔진에 의해 바이트코드로 변환된다.
2) 기계어로 변환
CPU마다 기계어를 다르게 해석하기에 가상 머신은 최적화된 기계어를 제작해낸다. 이 가상머신 덕분에 개발자는 따로 CPU별로 최적화된 기계어를 만들어낼 필요는 없다.
3) CPU 코드 실행
기계어를 실행하여 데이터 저장 및 연산 작업을 진행한다.
이러한 자바스크립트는 인터프리터 언어로서 기능을 해왔지만, 점차 웹에서도 다양한 요구사항들이 추가되면서 더 많은 기능들을 갖추어야 했고 이는 자바스크립트가 점차 성능상 무거워지는 계기가 되었다.
한편, 2009년 당시 구글은 웹에서 이용가능한 지도인 구글맵스를 개발하려고 있었는데 지도 어플리케이션은 사용자 상호작용이 많이 필요한 만큼 성능상 개선이 필요했고 이를 개선하고자 내놓은 것이 바로 Chrome V8
엔진이다.
이를 통해 자바스크립트 언어에서도 컴파일을 진행하게 된 계기가 되었다.
V8 엔진에 의해서 어떻게 자바스크립트도 컴파일과정을 거치는 걸까?
V8 엔진은 기존의 Parser를 거쳐 AST로 변환된 내용을 인터프리터에게 전달하는 과정에 덧붙여 자바스크립트 변환과정을 진행한다.
위 그림에서 자바스크립트가 Parser, AST, Interpreter를 거쳐 ByteCode로 변모하는 것은 V8 엔진이 등장하기 전까지의 JS의 모습이다. 이에 추가적으로 Profiler
라는게 등장한다. 이 Profiler
는 인터프리터를 관찰하며 실행되는 코드를 계속해서 모니터링 한다. 모니터링하는 과정에 코드내에 반복 실행되는 것이 있다면 이를 컴파일러에게 넘겨 실시간으로 컴파일 하도록 한다. 이를 통해 최적화된 바이트 코드를 생성해내며, 자바스크립트가 동적 웹 환경에서 빠르게 동작할 수 있도록 한다.
이처럼 V8 같은 고성능 자바스크립트 엔진은 필요할때 마다 컴파일 하는 컴파일러를 'Just-In-Time (JIT)' 라고 부른다. 또한 필요할 경우 Decompile
과정을 진행하는데 이는 컴파일러가 판단할때 컴파일하는게 좋다고 판단했던 것이 잘못되었음을 알고 되돌리는 과정이다. 이는 컴파일 하는 비용을 줄이기 위함이라고 한다.