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배
라는 획기적인 성능 향상을 가져온 특정 최적화 작업을 다룹니다. 이 작업은 전체 점수의 괄목할 만한 상승에 기여했습니다. 최적화는 벤치마크에서 영감을 받았지만, 이러한 패턴은 실제 코드에서도 나타나고 있습니다.
자바스크립트 프로미스 통합(JSPI) API는 외부 기능에 대한 동기적 접근을 가정하여 작성된 웹어셈블리 애플리케이션이 실제로는 _비동기적_인 환경에서도 원활히 작동할 수 있도록 합니다.
WebAssembly의 JavaScript Promise Integration (JSPI) API에 새로운 API가 추가되었으며 Chrome M126 릴리스에서 사용할 수 있습니다. 변경된 사항, Emscripten과 함께 사용하는 방법, 그리고 JSPI를 위한 로드맵에 대해 논의합니다.
JSPI는 순차적인 API를 사용하는 WebAssembly 애플리케이션이 비동기적인 웹 API에 접근할 수 있도록 하는 API입니다. 많은 웹 API는 JavaScript Promise
객체를 바탕으로 만들어졌습니다: 요청된 작업을 즉시 수행하는 대신, 이를 수행하기 위한 Promise
를 반환합니다. 반면에, WebAssembly로 컴파일된 많은 애플리케이션은 호출자가 완료될 때까지 대기하는 API가 지배적인 C/C++ 세계에서 유래됩니다.
약 3년간 초기 설계 문서 및 그동안의 수백개의 CL 이후, V8 샌드박스 — V8를 위한 경량의 프로세스 내 샌드박스 — 는 이제 더 이상 실험적 보안 기능으로 간주되지 않을 만큼 발전했습니다. 오늘부터 V8 샌드박스는 Chrome's Vulnerability Reward Program (VRP)에 포함되었습니다. 강력한 보안 경계를 형성하기 전에 해결해야 할 문제들이 아직 남아 있지만, VRP 포함은 해당 방향으로 중요한 단계입니다. 따라서 Chrome 123은 샌드박스의 일종의 "베타" 릴리스로 간주될 수 있습니다. 이 블로그 게시물은 샌드박스의 동기를 논의하고, V8에서의 메모리 손상이 호스트 프로세스 내에서 확산되는 것을 어떻게 방지하는지 보여주며, 궁극적으로 왜 메모리 안전을 향한 필수 단계인지 설명하는 기회로 사용됩니다.
WebAssembly의 JavaScript Promise Integration(JSPI) API가 Chrome M123 릴리스와 함께 오리진 트라이얼에 진입합니다. 이를 통해 여러분과 사용자들이 이 새로운 API로부터 이점이 있는지 테스트할 수 있습니다.
JSPI는 순차적 코드라고 불리는 코드를 WebAssembly로 컴파일한 후 비동기적인 웹 API에 액세스할 수 있도록 하는 API입니다. 많은 웹 API는 JavaScript의 Promise
를 기반으로 설계되어 요청된 작업을 즉시 수행하는 대신 그 작업을 수행하겠다는 Promise
를 반환합니다. 작업이 최종적으로 수행되면 브라우저의 작업 실행기가 Promise
와 함께 콜백을 호출합니다. JSPI는 이 구조에 연결되며, WebAssembly 애플리케이션이 Promise
가 반환될 때 중단되고, Promise
가 완료될 때 다시 실행되는 기능을 제공합니다.
undefined
, true
와 같은 핵심 JavaScript 객체들이 어디에서 오는지 궁금해해 본 적이 있나요? 이러한 객체들은 사용자가 정의한 객체의 원소이며, 먼저 존재해야 합니다. V8은 이들을 이동 불가, 불변의 루트로 간주하며, 읽기 전용 힙이라는 자체 힙에 저장합니다. 이들이 끊임없이 사용되기 때문에, 빠른 액세스가 필수적입니다. 그렇다면 이들의 메모리 주소를 컴파일 시간에 정확히 추측할 수 있다면 얼마나 빠를까요?
V8의 짜릿한 세계에 오신 것을 환영합니다. 여기서는 속도가 단순한 기능이 아닌 삶의 방식입니다. 2023년을 보내며 V8이 올해 이룩한 놀라운 성과를 축하할 때입니다.
혁신적인 성능 최적화를 통해 V8은 웹의 끊임없이 진화하는 환경에서 가능한 것의 경계를 계속해서 넓혀가고 있습니다. 우리는 새로운 중간 단계 컴파일러를 도입하고, 최고 단계 컴파일러 인프라, 런타임 및 가비지 컬렉터에 여러 가지 개선을 적용하여 전반적으로 상당한 속도 향상을 이루었습니다.
Chrome M117에서 우리는 새로운 최적화 컴파일러인 Maglev을 소개했습니다. Maglev은 기존의 Sparkplug와 TurboFan 컴파일러 사이에 자리 잡으며, 적당히 좋은 코드와 적당히 빠른 속도로 생성하는 빠른 최적화 컴파일러 역할을 합니다.
2021년까지 V8에는 두 가지 주요 실행 계층이 있었습니다: 인터프리터 Ignition 및 TurboFan, V8의 성능 극대화를 목표로 한 최적화 컴파일러. 모든 JavaScript 코드는 먼저 Ignition 바이트코드로 컴파일되고 인터프리팅되어 실행됩니다. 실행되는 동안 V8은 프로그램의 행동을 추적하며 객체의 형태와 타입을 추적합니다. 실행 메타데이터와 바이트코드는 최적화 컴파일러에 전달되어 인터프리터보다 훨씬 빠르게 실행되는 고성능의 종종 추측적인 머신 코드로 생성됩니다.