V8에 미리 알리기: 명시적인 컴파일 힌트를 사용한 더 빠른 자바스크립트 시작
빠르게 자바스크립트를 실행하는 것은 반응형 웹 앱을 위한 핵심입니다. V8의 고급 최적화에도 불구하고, 중요한 자바스크립트를 시작 시점에 파싱하고 컴파일하는 것은 여전히 성능 병목을 초래할 수 있습니다. 초기 스크립트 컴파일 동안 어떤 자바스크립트 함수를 컴파일할지를 알면 웹 페이지 로딩 속도를 높일 수 있습니다.
빠르게 자바스크립트를 실행하는 것은 반응형 웹 앱을 위한 핵심입니다. V8의 고급 최적화에도 불구하고, 중요한 자바스크립트를 시작 시점에 파싱하고 컴파일하는 것은 여전히 성능 병목을 초래할 수 있습니다. 초기 스크립트 컴파일 동안 어떤 자바스크립트 함수를 컴파일할지를 알면 웹 페이지 로딩 속도를 높일 수 있습니다.
V8의 최종 단계 최적화 컴파일러인 Turbofan은 대규모 생산 컴파일러 중에서 드물게 Sea of Nodes (SoN)을 사용하는 것으로 유명합니다. 그러나 약 3년 전부터 우리는 Sea of Nodes를 제거하고 더 전통적인 Control-Flow Graph (CFG) Intermediate Representation (IR)로 되돌아가기 시작했습니다. 이 새로운 IR을 우리는 Turboshaft라고 명명했습니다. 현재 Turbofan의 JavaScript 백엔드는 전부 Turboshaft를 사용하고 있으며, WebAssembly 파이프라인 전체에서도 Turboshaft를 사용하고 있습니다. Turbofan의 두 부분은 여전히 Sea of Nodes를 일부 사용하는데, 하나는 내장 파이프라인이며, 이를 천천히 Turboshaft로 교체하고 있으며, 다른 하나는 JavaScript 파이프라인의 프론트엔드로 이는 또 다른 CFG 기반 IR인 Maglev로 교체 중입니다. 이 블로그 글에서는 우리가 Sea of Nodes를 벗어나기로 한 이유를 설명합니다.
V8에서는 JavaScript 성능을 지속적으로 개선하고 있습니다. 이러한 노력의 일환으로 최근 JetStream2 벤치마크 스위트를 재검토하여 성능 급락 현상을 제거했습니다. 이 글에서는 async-fs
벤치마크에서 2.5배
라는 획기적인 성능 향상을 가져온 특정 최적화 작업을 다룹니다. 이 작업은 전체 점수의 괄목할 만한 상승에 기여했습니다. 최적화는 벤치마크에서 영감을 받았지만, 이러한 패턴은 실제 코드에서도 나타나고 있습니다.
undefined
, true
와 같은 핵심 JavaScript 객체들이 어디에서 오는지 궁금해해 본 적이 있나요? 이러한 객체들은 사용자가 정의한 객체의 원소이며, 먼저 존재해야 합니다. V8은 이들을 이동 불가, 불변의 루트로 간주하며, 읽기 전용 힙이라는 자체 힙에 저장합니다. 이들이 끊임없이 사용되기 때문에, 빠른 액세스가 필수적입니다. 그렇다면 이들의 메모리 주소를 컴파일 시간에 정확히 추측할 수 있다면 얼마나 빠를까요?
V8의 짜릿한 세계에 오신 것을 환영합니다. 여기서는 속도가 단순한 기능이 아닌 삶의 방식입니다. 2023년을 보내며 V8이 올해 이룩한 놀라운 성과를 축하할 때입니다.
혁신적인 성능 최적화를 통해 V8은 웹의 끊임없이 진화하는 환경에서 가능한 것의 경계를 계속해서 넓혀가고 있습니다. 우리는 새로운 중간 단계 컴파일러를 도입하고, 최고 단계 컴파일러 인프라, 런타임 및 가비지 컬렉터에 여러 가지 개선을 적용하여 전반적으로 상당한 속도 향상을 이루었습니다.
Chrome M117에서 우리는 새로운 최적화 컴파일러인 Maglev을 소개했습니다. Maglev은 기존의 Sparkplug와 TurboFan 컴파일러 사이에 자리 잡으며, 적당히 좋은 코드와 적당히 빠른 속도로 생성하는 빠른 최적화 컴파일러 역할을 합니다.
2021년까지 V8에는 두 가지 주요 실행 계층이 있었습니다: 인터프리터 Ignition 및 TurboFan, V8의 성능 극대화를 목표로 한 최적화 컴파일러. 모든 JavaScript 코드는 먼저 Ignition 바이트코드로 컴파일되고 인터프리팅되어 실행됩니다. 실행되는 동안 V8은 프로그램의 행동을 추적하며 객체의 형태와 타입을 추적합니다. 실행 메타데이터와 바이트코드는 최적화 컴파일러에 전달되어 인터프리터보다 훨씬 빠르게 실행되는 고성능의 종종 추측적인 머신 코드로 생성됩니다.
V8 v9.1에서는 데스크톱 환경에서 내장 기능을 일시적으로 비활성화했습니다. 내장 기능은 메모리 사용을 크게 개선하지만, 내장 기능과 JIT(Just-In-Time) 컴파일된 코드 간 함수 호출이 상당한 성능 저하를 일으킬 수 있음을 발견했습니다. 이 비용은 CPU의 마이크로아키텍처에 따라 달라질 수 있습니다. 이 게시물에서는 이러한 현상이 발생하는 이유, 성능 측면에서 어떻게 보이는지, 그리고 장기적으로 이를 해결하기 위한 계획에 대해 설명하겠습니다.
super
키워드는 객체의 부모에 있는 프로퍼티와 함수에 접근하기 위해 사용될 수 있습니다.
이전에 super
프로퍼티 접근(super.x
등)은 런타임 호출을 통해 구현되었지만, V8 v9.0부터는 인라인 캐시 시스템(IC)을 비최적화 코드에서 재사용하고 런타임으로 점프하지 않고 super
프로퍼티 접근을 위한 적절한 최적화 코드를 생성합니다.