V8 Engine
by Alex
[번역] How the V8 engine works?
http://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/
구글의 V8엔진이 어떻게 동작하지는 알아보기위해 위 내용을 번역하기로 했다.
V8엔진은 어떻게 동작하는가?
V8엔진은 독일 구글 개발 센터에서 만들어진 javascript엔진이다. 이것은 오픈소스이며, c++을 통해 개발 되었다. 클라이언트(Google Chrome), 서버(node.js)에서 모두 사용되는 Javascript 어플리케이션이다.
V8엔진은 웹브라우저안에서 자바스크립트의 실행성능을 높이기 위해 디자인되었다. 속도를 얻기위해서, V8은 interpreter를 사용하는 대신 javascript 코드를 효율적인 machine 코드로 변환한다. SpiderMonkey 또는 Rhino (Mozilla)와 같은 최신 javascript 엔진 처럼 JIT(Just-In-Time) compiler를 구현하여 javascript 코드를 실행시 컴파일하여 machine 코드로 변환한다. V8의 가장 큰 차이는 byte code 또는 어떤 intermediate code를 생성하지 않는다.
이 글에서 중점적으로 봐야하는 것은 V8엔진이 클라이언트, 서버단에서 최적화된 코드를 생성하기 위해 어떻게 동작하고 있는지 이해하는 것이다. 만약 당신이 “내가 javascript의 성능에 관심을 가져야 하나요?”라고 묻는다면, 나는 Daniel Clifford (V8팀의 기술 책임자 겸 관리자)의 말을 인용하여 대답 할 것이다.
“이것은 현재의 어플리케이션을 더욱 빠르게 실행되도록 할 뿐만 아니라, 이전에 불가능 했던일을 가능하게 합니다.”
Hidden class
- Javascript는 Prototype 기반 언어이다. class가 없고, 복제 과정을 사용하여 object를 만든다.
- Javascript는 또한 동적으로 typed 된다. 타입과 타입정보가 명확하지 않고 실행중 object의 property들이 추가되거나 삭제될 수 있다. 타입과 poroperties에 효율적으로 접근할수 있도록 만드는 것이 V8의 첫번쨰 큰 과제였다. object에 property를 저장하고 property의 위치를 동적으로 탐색하기 위해 dictionary-like 자료 구조를 사용하는 대신(많은 javascript 엔진에서 사용)에 V8은 type system을 내부적으로 표현하고 property의 접근 시간을 줄이기 위해 runtime에 Hidden Class를 생성한다.
예를 들어 Point Function
을 통해 두개의 point instance
를 생성해보자!
만약 layout이 동일한 경우 p,q는 V8에 의해 생성된 hidden class에 속한다. 이것은 hidden class 사용의 또 다른 장점을 부각시킨다.: V8은 동일한 object의 properties를 그룹화 할수 있다. 여기서 p,q는 동일한 optimized code(최적화 코드)를 사용한다.
이제, z property를 q object 선언 직후에 추가한다고 가정해보자. (동적타입 언어에서는 아무 문제가 없다).
V8은 어떻게 이 시나리오에 대응할수 있을까? 사실, V8은 생성자 함수가 property를 선언 할떄 마다 새로운 hidden class를 생성하고 hidden class의 변화를 추척한다. 왜일까? 두개의 object(p,q)가 생성되었고 두번째 object q
가 생성된후에 property가 추가 되었다면, V8은 새로운 멤버와 함께 마지막 hidden class(첫번째 객체 p)를 생성하고 새로운 객체(두번째 객체 q)를 생성해야한다.
새로운 hidden class를 생성 할때마다, 이전의 것은 변경되었다는 표시와 함께 갱신되어야 한다. 새로 생성된 hidden class가 이전의 것을 대신해서 사용되어야 하기 때문이다.
Code Optimization
V8은 각각의 property마다 새로운 hidden class를 생성하기 떄문에 hidden class 생성은 최소한으로 유지되어야 한다. 이것을 하려면, object 생성후 property를 추가하는 것을 피해야하고, 항상 동일한 순서로 object 멤버를 초기화해야한다. (hidden class의 다른 트리 생성을 피하기 위해)
[Update] 다른 trick: Monomorphic operations(단일 동형 연산)은 같은 hidden class를 가진 object에서만 동작한다. V8은 function이 호출되는 시점에 hidden class를 생성한다. 다른 매개변수 타입으로 호출하게 되면, V8은 새로운 hidden class를 생성한다. Polymorphic code 보다 Monomorphic code를 선호해라.
V8의 javascript 코드 최적화 예제들
Tagged values
numbers와 javascript object를 효과적으로 표현하기위해서 V8은 두가지 모두 32bit 값으로 나타낸다. V8은 object(flag: 1)인지 integer(flag: 0) 알기위해서 SMall Integer
또는 SMI로 불리는 하나의 비트를 사용하고 이 때문에 값은 31bits이다. 이때, numeric value가 31bits 보다 크면 V8은 숫자를 감싸서 double로 만들고 이 숫자를 넣을 새로운 object를 생성한다.
Code optimization: javascript object에 값을 넣으려면 비싼 boxing 연산을 피하기 위해 31bits의 signed number을 사용하는 것이 좋다.
Arrays
V8은 Array를 조작하기위해 2개의 다른 방법을 사용한다.
- Fast elements: arrays를 설계하기 위해 key세트는 아주 간결하다. 그들은 아주 효율적으로 접근하기위해 linear storage buffer를 가지고 있다.
- Dictionary elements: 모든 요소들이 없는 sparse array를 위해 고안되어는데 이것은 사실 해시테이블이다. Fast elements 방식보다 더 많은 비용이 든다.
Code optimization: V8이 array를 처리하는데 Fast elements 방식을 사용하는 확인해야한다. 미리 커다란 배열을 할당하지말고 사용하면서 크기가 커지도록 한다. 마지막으로 배열의 요소를 삭제하지 않는것이 좋다. 이것은 key세트를 부족하게 만든다.
V8은 javascript 코드를 어떻게 compile 할까?
V8은 두개의 컴파일러를 가지고 있다.
-
모든 javscript에 적합한 코드를 생성할수 있는
Full Compiler
: 좋지만 훌륭한 JIT code는 아니다. 이 컴파일러의 목표는 코드를 신속하게 생성하는 것이다. 이러한 목적을 달성하기 위해 아무런 type을 분석하지 않으며, type 자체를 모른다. 대신에 Inline Caches 또는 ‘IC’ 전략을 사용하여 프로그램이 실행되는 동안 타입을 정제한다. IC는 매우 효율적이며 속도는 20배 정도 향상된다. -
모든 javascript 언어에 대해 훌륭한 코드를 생성하는
Optimazing Compiler
: 이것은 나중에 나왔으며, hot function(여러번 실행되는 함수를 의미)을 재 컴파일한다. Optimazing Compiler는 Inline Chache에서 타입을 얻고 코드를 최적화 할 수 있는 방법을 결정한다. 하지만, 몇몇 언어는 try / catch 블럭 같은 것을 지원하지 않는다. (try/catch 블록에 대한 최적화 작업은 “불안정한” 코드를 함수로 작성하고 try 블록에서 그 함수를 호출하려는 것으로 시도한다.)
Code optimization: V8은 또한 역최적화를 지원한다. 최적화 컴파일러는 다른 타입들에 대하여 Inline Chache로 부터 적합한 추론을 한다. 만약 이 추론이 맞지 않다면 역최적화를 진행한다. 예를 들어, 만약 예상하지 않은 hidden class가 생성된다면, V8은 최적화된 코드를 버리고 Full Compiler로 돌아와 Inline Chache로 부터 다시 타입을 얻는다. 이러한 과정은 느리고, 최적화 된 function을 변경하려는 시도는 피하는 것이 좋다.
참고
- 동적타입, 정적타입 언어: http://itmining.tistory.com/65
- 런타임(runtime): http://asfirstalways.tistory.com/99
- 컴파일: http://karfn84.tistory.com/entry/%EC%BB%B4%ED%93%A8%ED%84%B0-%EC%9D%BC%EB%B0%98-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EC%9D%B4%EB%9E%80
- https://www.html5rocks.com/ko/tutorials/speed/v8/
- https://engineering.huiseoul.com/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80-v8-%EC%97%94%EC%A7%84%EC%9D%98-%EB%82%B4%EB%B6%80-%EC%B5%9C%EC%A0%81%ED%99%94%EB%90%9C-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%9E%91%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8B%A4%EC%84%AF-%EA%B0%80%EC%A7%80-%ED%8C%81-6c6f9832c1d9
- Google I/O 2012 “Breaking the JavaScript Speed Limit with V8” with Daniel Clifford, tech lead and manager of the V8 team: video and slides.
- V8: an open source JavaScript engine: video of Lars Bak, V8 core engineer.
- Nikkei Electronics Asia blog post: Why Is the New Google V8 Engine So Fast?
Subscribe via RSS