The race for speed part 2: How JavaScript compilers work

 
 

 
 
우리는 자바스크립트 엔진에 대해 이야기할때 일반적으로 컴파일러를 말한다. 인간이 읽을수 있는 소드 코드(자바스크립트의 경우)를 만들면 컴파일러는 컴퓨터를 위해 이를 기계가 읽을 수 있는 명령어를 생성하는 프로그램이다. 컴파일러가 실행될 때 우리의 코드가 어떤일이 발생하는지 고려하지 않는다면 신비하고 영리한 코딩이라기 보다는 기본적으로 번역 연습이라고 할 수 있다. 빠른 실행 코드를 만드는 것은 영리한 것이다.

 

How a simple compiler works

자바스크립트는 높은 레벨의 언어 로 여겨진다. 이 말은 사람이 읽을 수 있고 높은 유연성을 가지고 있다는 뜻이다. 컴파일러의 작업은 높은 레벨의 코드를 본래의 컴퓨터 명령어로 변환하는 것이다.
 
 

 
 
간단한 컴파일러는 4단계 프로세스가 있을 것이다. : 렉서, 파서, 번역 및 통역
 

  1. 렉서 또는 어휘 분석기는 소스 코드를 스캔하고 토큰이라고 하는 작은 단위로 변환한다. 이것은 일반적으로 정규표현식을 사용하여 패턴과 매칭시켜 만들어 진다.
  2. 토큰 화 코드는 문법이 맞는지 식별하기 위해 파서를 통과하고 구문 트리라 불리는 문법 구조로 인코딩한다.
  3. 이 그래프 모양의 구조는 바이트 코드로 변환하기 위해 변환기를 통과한다. 가장 간단한 구현은 바이트 코드와 동등하게 토큰을 거대한 switch 문장으로 매핑하는 것이다.
  4. 바이트 코드는 바이트 코드 인터프리터를 통해 원시코드로 변환되고 렌더링된다.

 
이렇게 디자인된 고전적인 컴파일러는 수년 동안 나돌고 있다. 하지만 브라우저가 컴퓨터에 보여지는 부분(바탕화면)의 요구사항은 많이 다르다. 고전적인 설계는 다수 방법에 불충분하다. 문제가 해결되는 혁실적인 방법은 브라우저에서의 속도 경쟁 이야기다.
 
 
Fast, Slim, Correct
자바스크립트는 매우 유연하고 분명하지 않은 프로그래밍 구조에 꽤 관대하다. 그럼 당신은 late-bindingloosely-typed, dynamic language에 대한 컴파일을 작성하기 위해 어떻게 하는가? 그것을 빨리하기 전에 먼저 정확하게 만들거나 Brendan Eich처럼 지적해라.

“Fast, Slim, Correct. Pick any two, so long as one is ‘Correct’”

컴파일러의 정확함을 테스트하기 위한 혁신적인 방법은 “fuzz”하는 것이다. Mozilla’s Jesse Ruderman 는 이 목적을 정확히 하기 위해 jsfunfuzz를 만들었다. Brendan은 이것을 “JavaScript travesty generator”라고 부른다. 왜냐면 그 목적은 자바스크립트에 대응하는 구문인지를 보기 위해 컴파일러에 공급하는 이상하지만 유효한 자바스크립트 구조를 만드는 것이기때문이다. 이 종류의 툴은 컴파일러 버그나 특정한 경우에 엄청나게 유용하다.

 
 
JIT Compilers
고전적인 설계 원리 문제는 런타임 바이트 코드 해석 속도가 느린 것이다. 그 성능은 기계 코드로 바이트 코드를 변환하는 컴파일 단계를 추가하여 향상시킬 수 있다. 하지만 한 웹페이지를 완전히 컴파일을 하기 위해 몇 분을 기다려야하는 브라우저는 환영받지 못한다.
이 문제의 해결책은 JIT의 “lazy compilation” 이거나 Just In Time compiler이다. 이름이 뜻하듯이 당신이 컴파일을 필요하는 시간에 기계 코드의 일부를 컴파일한다. JIT 컴파일러는 각각의 최적화를 위한 전력과 범주가 다양하다. 어떤 사람들은 정규 표현식 컴파일러는 단일 작업을 최적화하는 것을 임무라고 말하고 반면 다른 사람들은 루프나 함수와 같은 일반적인 작업을 최적화할 수 있다고 말한다. 근래에는 자바스크립트 엔진은 모든 코드의 성능을 향상시키기 위해 몇몇의 컴파일러를 함께 작동한다.

 
 
JavaScript JIT compilers
첫 번째 자바스크립트 JIT 컴파일러는 Mozilla’s TraceMonkey였다. 이는 일반적으로 실행되는 코드 루프를 찾고 코드를 통해 경로를 추적하기 때문에 “tracing JIT” 라고도 불렸다. 이러한 “hot loops”는 기계코드로 컴파일되었다. Mozilla라는 이전 엔진에 비해 20%에서 40%이상의 성능 향상을 달성할 수 있었다.
TraceMonkey가 출시되자 마자 Google은 새로운 V8 자바스크립트 엔진을 적용한 Chrome 브라우저를 출시했다. V8은 빠른 실행을 위해 특별히 설계되었다. 주요 설계의 중점은 바이트 코드 생성을 완전히 생략하고 대신 네이티브 코드 번역기를 사용했다. 출시한지 일년 이내에 V8팀은 레지스터 할당을 구현했고 인라인 캐싱을 향상하여 10배 빠른 정규 표현식 엔진을 재작성했다. 자바스크립트 실행은 전체 속도를 150% 증가시켰다. 그것은 고속화를 위한 경쟁이었다.
Mozilla’s 최근에 브라우저 벤더는 한 단계를 추가해 최적화 컴파일러를 도입했다. Directed Flow Graph (DFG)나 구문 트리를 생성 한 후, 컴파일러가 기계어 코드 생성 이전에 더 최적화를 수행하기 위해 이 정보를 사용할 수 있다. Mozilla’s IonMonkey 와 Google’s Crankshaft 는 DFG 컴파일러의 예이다.
이 모든 독창성의 야심 찬 목표는 네이티브 C 코드 만큼 빠르게 자바 스크립트 코드를 실행하는 것이다. 이 목표는 심지어 몇년전까지만 해도 우스운듯했지만 점점 가까워지고 있다. 3 부에서는 컴파일러 설계자가 더 빠른 자바스크립트를 생성하는데 사용하는 몇가지 전략을 살펴보겠다.
 
 
 
원문 출처 : http://creativejs.com/2013/06/the-race-for-speed-part-2-how-javascript-compilers-work/


0개의 댓글

답글 남기기

아바타 플레이스홀더

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다