1.6 인터프리터 이해하기
Last updated
Last updated
인인터프리터, 스크립트 언어의 실행 절차인터프리터, 스크립트 언어의 실행 절차인ㅇㅇJS는 인터프리터 언어인가, 컴파일러 언어인가?
이에 대한 중론은 '스크립트 언어다'
프로그래밍 언어 발전사에서 인터프리터 언어와 스크립트 언어는 컴파일 언어에 비해 열약하다고 평가받아왔다. 성능 최적화가 잘 안 된다는 인식 + 일부 스크립트 언어에서 동적 타입(더 성숙한 방식) 대신 정적 타입을 사용하기 때문이다.
컴파일을 거치면 분산 시스템에서 언제든 배포할 수 있는 바이너리 파일이 생성된다. 하지만, JS는 소스 코드 자체를 배포하기 때문에 컴파일러 언어가 아니라고 주장한다. 인터프리터 언어인지 컴파일러 언어인지에 따라 배포 방식이 달라지는데, 오늘날에는 배포 방식이 더 이상 중요하지 않다고 주장하는 이들이 늘고 있다.
인터프리터 언어인지 컴파일 언어인지 명확히 이해하고 있어야 JS가 오류를 어떻게 처리하는지 알 수 있다.
위에서 아래로 한 줄씩 코드가 실행되는 방식이며 실행이 시작되기 전에 거치는 사전 단계가 없다. (5번째 줄에서 오류가 있다면 4번째 줄이 실행되기 전까지 오류 발견X)
오류는 부적한 값이 할당된 변수, 값 같은 런타임 조건이나 잘못된 문이나 명령 때문일 수 있다. 상황에 따라 오류가 있는 줄까지 오류 처리를 미루는 작업이 괜찮을 수도 괜찮지 않을 수도 있다.
프로그램이 실행되기 전에 사전 단계 파싱을 거치는 언어도 있다. 파싱과 컴파일을 거치는 언어의 5번째 줄에 유효하지 않은 명령이 있다면 파싱 단계에서 오류가 발견된다. (사전에 오류 차단 가능, 굳이 실행X) 실행 전에 오류가 포함된 코드 조각이 어디 있는지 알면 구문 오류(syntax error)를 차단하기 좋다.
모든 컴파일 언어가 파싱을 거친다.
파싱이 끝나면 언젠가는 컴파일이 진행될 거라고 예상한다. 파싱이 완전히 끝난 다음에는 파싱 결과인 추상 구문 트리(abstract syntax tree)를 컴퓨터가 실행할 수 있는 형태로 바꿔주는 작업이 이어진다. 파싱을 거치는 언어는 파싱에서 끝나는게 아니라 실행 가능한 코드를 생성하는 작업까지 생성한다. → 파싱을 거치는 언어는 컴파일 언어라고 통용
JS로 작성한 소스 코드는 실행 전에 파싱을 거친다. 명세서에서는 중복된 매개변수명 가타이 정적으로 탐지가 가능한 오류: 초기 오류로 프로그램 실행 전에 초기 오류를 찾아낼 수 있어야 한다고 언급한다. 파싱이 없다면 이런 오류를 사전에 탐지할 수 없다.
JS는 파싱을 거치는 언어인데, 컴파일 언어이기도 한 걸까?
'아니요' 보단 '예'에 가깝다. JS에서 파싱이 끝난 코드는 한 줄씩 처리가 아닌, 컴파일러를 거쳐 최적화된 이진 코드로 변환 후 실행된다. (대부분의 언어와 엔진은 비효율성 때문에 파싱이 끝난 코드를 한 줄씩 실행하지 않는다.)
⭐️ 가상 머신에 전달할 이진 바이트 코드가 생성된다.
가상 머신의 역할이 전달받은 바이트 코드를 해석하는 것이라고 하지만, 이런 관점에서는 자바를 비롯한 JVM 기반 언어가 컴파일이 아닌 인터프리터 언어라고 해석하게 된다. 자바 등의 언어가 컴파일 언어라는 보편적인 주장에 모순이 생긴다. 자바와 JS는 완전히 다른 언어이지만 인터프리터와 컴파일 관점에서는 비슷한 점이 많다.
⭐️ JS 엔진은 파싱 이후 생성된 코드를 다양한 방법으로 실행 전에 그때그때(JIT just-in-time) 처리 및 최적화 한다.
이런 JS 엔진 작동 방식으로 인해 관점에 따라 JS를 컴파일 언어 혹은 인터프리터 언어라고 할 수 있다.
JS로 만든 소스코드가 실행될 때까지의 절차
처음 질문으로 돌아가서, JS는 그림 1-1처럼 한 줄씩 실행되는 인터프리터 언어일까, 1-2,1-3처럼 몇 단계를 거쳐 실행되는 언어일까? 완전한 사실은 아니지만, 필자는 JS가 컴파일 언어라고 생각한다.
JS가 컴파일 언어라고 생각하는 것은 중요하다. 개발자가 이상한 문법을 입력하는 실수를 하더라도 코드 실행 전에 정적 오류를 미리 발견할 수 있다는 특징이 있다. 이런 JS 방식은 기존 스크립트 프로그램과 상당히 다른 방식으로 개발할 수 있도록 한다. (당연히 더 도움되는 방식)
JS로 작성한 코드를 얼마나 빨리 파싱, 컴파일, 실행할 수 있는지에 대한 논의는 JS의 발전을 이끈 주요 주제이다.
도구 기반으로 만든 프로그램이 JS 엔진에서 더 효율적으로 처리된다는 사실이 ASM.js에 의해 입증된 이후, 모질라 재단의 엔지니어를 시작으로 여러 엔지니어 그룹이 웹어셈블리(WebAssembly) Wasm라는 기술을 공개하기 시작했다.
JS 코드와 스타일이 다르지만, JS 부분집합으로 인정되는 JS이다. 일관성 있는 타입 시스템을 사용하여 성능 최적화가 매우 뛰어나다.사람이 작성한 코드가 아니고, C 등의 언어로 작성한 코드를 트랜스파일 한 것으로 코드 생성 과정에서 자동으로 타입 관련 주석이 붙는다.
JS가 주력이 아닌 개발자도 JS 엔진에서 돌아가는 코드를 쉽게 작성할 수 있게 해주는 데 목적이 있다. (ASM.js 철학과 유사) 다만, 일반 JS와는 완전히 다른 프로그램 형태로 제작되어 실행 전 단계인 파싱과 컴파일을 거치지 않아 파싱과 컴파일에 따른 본질적인 지연을 피하는데 있어 ASM.js와는 다르다.
어셈블리 언어와 유사하며 JS 엔진의 일반적인 처리 프로세스와 달리 파싱, 컴파일 없이 처리된다. Wasm으로 만든 프로그램의 파싱, 컴파일은 실행 직전에 일어나고, 배포는 JS 엔진의 별도 처리가 많이 필요하지 않은 바이너리 파일 형식으로 진행된다.
Wasm은 성능 향상을 위해 만들어졌다. 웹 전용 기술이 아니며 JS도 아니다.
Wasm 때문에 JS가 더 이상 웹에서 사용되지 않거나 점유율이 줄어들거라고 주장한다. Wasm은 다른 언어들도 JS 엔진에서 실행할 수 있도록 하기 때문에 완전히 틀린 주장은 아니지만, JS를 대체하지는 못한다. JS를 포함에 웹에서 할 수 있는 것들을 확장하는 역할을 하는 기술이다.