This document explains techniques used by V8 in order to avoid having to re-compile and optimized JavaScript whenever an application that embeds it (i.e. Chrome or Node.js) starts up fresh.
Table of Contents generated with DocToc
- lessens overhead of parsing + compiling script
- uses cached data to recreate previous compilation result
- exposed via V8's API to embedders
- pass
v8::ScriptCompiler::kProduceCodeCache
as an option when compiling script- Note: V8 is deprecating
v8::ScriptCompiler::kProduceCodeCache
in favor ofv8::ScriptCompiler::GetCodeCache
- Note: V8 is deprecating
- cached data is attached to source object to be retrieved via
v8::ScriptCompiler::Source::GetCachedData
- can be persisted for later
- later cache data can be attached to the source object and passed
v8::ScriptCompiler::kConsumeCodeCache
as an option to cause V8 to bypass compileing the code and deserialize the provided cache data instead
- pass
- V8 6.6 caches top level code as well as code generated after script's top-level execution, which means that lazily compiled functions are included in the cache
Since Chrome embeds V8 it can make use of Code Caching and does so as follows.
- cold load: page loaded for the first time and thus no cached data is available
- warm load: page loaded before and caches compiled code along with the script file in disk
cache
- to qualify, the last load needs to be within the last 72 hours and the script source be larger than 1KB
- hot load: page loaded twice before and thus can use the cached compiled code instead of parsing + compiling the script again
- V8 uses snapshots and lazy deserialization to retrieve previously optimized code for builtin functions
- powerful snapshot API exposed to embedders via
v8::SnapshotCreator
- among other things this API allows embedders to provide an additional script to customize a start-up snapshot
- new contexts created from the snapshot are initialized in a state obtained after the script executed
- native C++ functions are recognized and encoded by the serializer as long as they have been registered with V8
- serializer cannot directly capture state outside of V8, thus outside state needs to be attached to a JavaScript object via embedder fields
- only about 30% of builtin functions are used on average
- deserialize builtin function from the snapshot when it is called the first time
- functions have well-known positions within the snapshot's dedicated builtins area
- starting offset of each code object is kept in a dedicated section within builtins area
- additionally implemented lazy deserializations for bytecode handlers, which contain logic to execute each bytecode within Ignition interpreter
- enabled in V8 v6.4 resulting in average V8's heap size savings of 540 KB
- custom startup snapshots - 2015 somewhat out of date as embedder API changed and lazy deserialization was introduced
- Energizing Atom with V8's custom start-up snapshot - 2017
- Lazy deserialization - 2018
- Speeding up Node.js startup using V8 snapshot