| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a62345e commit 58d2dad
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,11 @@ const { | |||
| 22 | 22 | const { getOptionValue } = require('internal/options'); | |
| 23 | 23 | const assert = require('internal/assert'); | |
| 24 | 24 | const { Buffer } = require('buffer'); | |
| 25 | + const { | ||
| 26 | + getCompileCacheEntry, | ||
| 27 | + saveCompileCacheEntry, | ||
| 28 | + cachedCodeTypes: { kStrippedTypeScript, kTransformedTypeScript, kTransformedTypeScriptWithSourceMaps }, | ||
| 29 | + } = internalBinding('modules'); | ||
| 25 | 30 | ||
| 26 | 31 | /** | |
| 27 | 32 | * The TypeScript parsing mode, either 'strip-only' or 'transform'. | |
@@ -105,11 +110,19 @@ function stripTypeScriptTypes(code, options = kEmptyObject) { | |||
| 105 | 110 | }); | |
| 106 | 111 | } | |
| 107 | 112 | ||
| 113 | + /** | ||
| 114 | + * @typedef {'strip-only' | 'transform'} TypeScriptMode | ||
| 115 | + * @typedef {object} TypeScriptOptions | ||
| 116 | + * @property {TypeScriptMode} mode Mode. | ||
| 117 | + * @property {boolean} sourceMap Whether to generate source maps. | ||
| 118 | + * @property {string|undefined} filename Filename. | ||
| 119 | + */ | ||
| 120 | + | ||
| 108 | 121 | /** | |
| 109 | 122 | * Processes TypeScript code by stripping types or transforming. | |
| 110 | 123 | * Handles source maps if needed. | |
| 111 | 124 | * @param {string} code TypeScript code to process. | |
| 112 | - * @param {object} options The configuration object. | ||
| 125 | + * @param {TypeScriptOptions} options The configuration object. | ||
| 113 | 126 | * @returns {string} The processed code. | |
| 114 | 127 | */ | |
| 115 | 128 | function processTypeScriptCode(code, options) { | |
@@ -126,6 +139,20 @@ function processTypeScriptCode(code, options) { | |||
| 126 | 139 | return transformedCode; | |
| 127 | 140 | } | |
| 128 | 141 | ||
| 142 | + /** | ||
| 143 | + * Get the type enum used for compile cache. | ||
| 144 | + * @param {TypeScriptMode} mode Mode of transpilation. | ||
| 145 | + * @param {boolean} sourceMap Whether source maps are enabled. | ||
| 146 | + * @returns {number} | ||
| 147 | + */ | ||
| 148 | + function getCachedCodeType(mode, sourceMap) { | ||
| 149 | + if (mode === 'transform') { | ||
| 150 | + if (sourceMap) { return kTransformedTypeScriptWithSourceMaps; } | ||
| 151 | + return kTransformedTypeScript; | ||
| 152 | + } | ||
| 153 | + return kStrippedTypeScript; | ||
| 154 | + } | ||
| 155 | + | ||
| 129 | 156 | /** | |
| 130 | 157 | * Performs type-stripping to TypeScript source code internally. | |
| 131 | 158 | * It is used by internal loaders. | |
@@ -142,12 +169,40 @@ function stripTypeScriptModuleTypes(source, filename, emitWarning = true) { | |||
| 142 | 169 | if (isUnderNodeModules(filename)) { | |
| 143 | 170 | throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING(filename); | |
| 144 | 171 | } | |
| 172 | + const sourceMap = getOptionValue('--enable-source-maps'); | ||
| 173 | + | ||
| 174 | + const mode = getTypeScriptParsingMode(); | ||
| 175 | + | ||
| 176 | + // Instead of caching the compile cache status, just go into C++ to fetch it, | ||
| 177 | + // as checking process.env equally involves calling into C++ anyway, and | ||
| 178 | + // the compile cache can be enabled dynamically. | ||
| 179 | + const type = getCachedCodeType(mode, sourceMap); | ||
| 180 | + // Get a compile cache entry into the native compile cache store, | ||
| 181 | + // keyed by the filename. If the cache can already be loaded on disk, | ||
| 182 | + // cached.transpiled contains the cached string. Otherwise we should do | ||
| 183 | + // the transpilation and save it in the native store later using | ||
| 184 | + // saveCompileCacheEntry(). | ||
| 185 | + const cached = (filename ? getCompileCacheEntry(source, filename, type) : undefined); | ||
| 186 | + if (cached?.transpiled) { // TODO(joyeecheung): return Buffer here. | ||
| 187 | + return cached.transpiled; | ||
| 188 | + } | ||
| 189 | + | ||
| 145 | 190 | const options = { | |
| 146 | - mode: getTypeScriptParsingMode(), | ||
| 147 | - sourceMap: getOptionValue('--enable-source-maps'), | ||
| 191 | + mode, | ||
| 192 | + sourceMap, | ||
| 148 | 193 | filename, | |
| 149 | 194 | }; | |
| 150 | - return processTypeScriptCode(source, options); | ||
| 195 | + | ||
| 196 | + const transpiled = processTypeScriptCode(source, options); | ||
| 197 | + if (cached) { | ||
| 198 | + // cached.external contains a pointer to the native cache entry. | ||
| 199 | + // The cached object would be unreachable once it's out of scope, | ||
| 200 | + // but the pointer inside cached.external would stay around for reuse until | ||
| 201 | + // environment shutdown or when the cache is manually flushed | ||
| 202 | + // to disk. Unwrap it in JS before passing into C++ since it's faster. | ||
| 203 | + saveCompileCacheEntry(cached.external, transpiled); | ||
| 204 | + } | ||
| 205 | + return transpiled; | ||
| 151 | 206 | } | |
| 152 | 207 | ||
| 153 | 208 | /** | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -77,10 +77,27 @@ v8::ScriptCompiler::CachedData* CompileCacheEntry::CopyCache() const { | |||
| 77 | 77 | // See comments in CompileCacheHandler::Persist(). | |
| 78 | 78 | constexpr uint32_t kCacheMagicNumber = 0x8adfdbb2; | |
| 79 | 79 | ||
| 80 | + const char* CompileCacheEntry::type_name() const { | ||
| 81 | + switch (type) { | ||
| 82 | + case CachedCodeType::kCommonJS: | ||
| 83 | + return "CommonJS"; | ||
| 84 | + case CachedCodeType::kESM: | ||
| 85 | + return "ESM"; | ||
| 86 | + case CachedCodeType::kStrippedTypeScript: | ||
| 87 | + return "StrippedTypeScript"; | ||
| 88 | + case CachedCodeType::kTransformedTypeScript: | ||
| 89 | + return "TransformedTypeScript"; | ||
| 90 | + case CachedCodeType::kTransformedTypeScriptWithSourceMaps: | ||
| 91 | + return "TransformedTypeScriptWithSourceMaps"; | ||
| 92 | + default: | ||
| 93 | + UNREACHABLE(); | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + | ||
| 80 | 97 | void CompileCacheHandler::ReadCacheFile(CompileCacheEntry* entry) { | |
| 81 | 98 | Debug("[compile cache] reading cache from %s for %s %s...", | |
| 82 | 99 | entry->cache_filename, | |
| 83 | - entry->type == CachedCodeType::kCommonJS ? "CommonJS" : "ESM", | ||
| 100 | + entry->type_name(), | ||
| 84 | 101 | entry->source_filename); | |
| 85 | 102 | ||
| 86 | 103 | uv_fs_t req; | |
@@ -256,7 +273,8 @@ void CompileCacheHandler::MaybeSaveImpl(CompileCacheEntry* entry, | |||
| 256 | 273 | v8::Local<T> func_or_mod, | |
| 257 | 274 | bool rejected) { | |
| 258 | 275 | DCHECK_NOT_NULL(entry); | |
| 259 | - Debug("[compile cache] cache for %s was %s, ", | ||
| 276 | + Debug("[compile cache] V8 code cache for %s %s was %s, ", | ||
| 277 | + entry->type_name(), | ||
| 260 | 278 | entry->source_filename, | |
| 261 | 279 | rejected ? "rejected" | |
| 262 | 280 | : (entry->cache == nullptr) ? "not initialized" | |
@@ -287,6 +305,25 @@ void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry, | |||
| 287 | 305 | MaybeSaveImpl(entry, func, rejected); | |
| 288 | 306 | } | |
| 289 | 307 | ||
| 308 | + void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry, | ||
| 309 | + std::string_view transpiled) { | ||
| 310 | + CHECK(entry->type == CachedCodeType::kStrippedTypeScript || | ||
| 311 | + entry->type == CachedCodeType::kTransformedTypeScript || | ||
| 312 | + entry->type == CachedCodeType::kTransformedTypeScriptWithSourceMaps); | ||
| 313 | + Debug("[compile cache] saving transpilation cache for %s %s\n", | ||
| 314 | + entry->type_name(), | ||
| 315 | + entry->source_filename); | ||
| 316 | + | ||
| 317 | + // TODO(joyeecheung): it's weird to copy it again here. Convert the v8::String | ||
| 318 | + // directly into buffer held by v8::ScriptCompiler::CachedData here. | ||
| 319 | + int cache_size = static_cast<int>(transpiled.size()); | ||
| 320 | + uint8_t* data = new uint8_t[cache_size]; | ||
| 321 | + memcpy(data, transpiled.data(), cache_size); | ||
| 322 | + entry->cache.reset(new v8::ScriptCompiler::CachedData( | ||
| 323 | + data, cache_size, v8::ScriptCompiler::CachedData::BufferOwned)); | ||
| 324 | + entry->refreshed = true; | ||
| 325 | + } | ||
| 326 | + | ||
| 290 | 327 | /** | |
| 291 | 328 | * Persist the compile cache accumulated in memory to disk. | |
| 292 | 329 | * | |
@@ -316,18 +353,25 @@ void CompileCacheHandler::Persist() { | |||
| 316 | 353 | // incur a negligible overhead from thread synchronization. | |
| 317 | 354 | for (auto& pair : compiler_cache_store_) { | |
| 318 | 355 | auto* entry = pair.second.get(); | |
| 356 | + const char* type_name = entry->type_name(); | ||
| 319 | 357 | if (entry->cache == nullptr) { | |
| 320 | - Debug("[compile cache] skip %s because the cache was not initialized\n", | ||
| 358 | + Debug("[compile cache] skip persisting %s %s because the cache was not " | ||
| 359 | + "initialized\n", | ||
| 360 | + type_name, | ||
| 321 | 361 | entry->source_filename); | |
| 322 | 362 | continue; | |
| 323 | 363 | } | |
| 324 | 364 | if (entry->refreshed == false) { | |
| 325 | - Debug("[compile cache] skip %s because cache was the same\n", | ||
| 326 | - entry->source_filename); | ||
| 365 | + Debug( | ||
| 366 | + "[compile cache] skip persisting %s %s because cache was the same\n", | ||
| 367 | + type_name, | ||
| 368 | + entry->source_filename); | ||
| 327 | 369 | continue; | |
| 328 | 370 | } | |
| 329 | 371 | if (entry->persisted == true) { | |
| 330 | - Debug("[compile cache] skip %s because cache was already persisted\n", | ||
| 372 | + Debug("[compile cache] skip persisting %s %s because cache was already " | ||
| 373 | + "persisted\n", | ||
| 374 | + type_name, | ||
| 331 | 375 | entry->source_filename); | |
| 332 | 376 | continue; | |
| 333 | 377 | } | |
@@ -363,17 +407,20 @@ void CompileCacheHandler::Persist() { | |||
| 363 | 407 | auto cleanup_mkstemp = | |
| 364 | 408 | OnScopeLeave([&mkstemp_req]() { uv_fs_req_cleanup(&mkstemp_req); }); | |
| 365 | 409 | std::string cache_filename_tmp = entry->cache_filename + ".XXXXXX"; | |
| 366 | - Debug("[compile cache] Creating temporary file for cache of %s...", | ||
| 367 | - entry->source_filename); | ||
| 410 | + Debug("[compile cache] Creating temporary file for cache of %s (%s)...", | ||
| 411 | + entry->source_filename, | ||
| 412 | + type_name); | ||
| 368 | 413 | int err = uv_fs_mkstemp( | |
| 369 | 414 | nullptr, &mkstemp_req, cache_filename_tmp.c_str(), nullptr); | |
| 370 | 415 | if (err < 0) { | |
| 371 | 416 | Debug("failed. %s\n", uv_strerror(err)); | |
| 372 | 417 | continue; | |
| 373 | 418 | } | |
| 374 | 419 | Debug(" -> %s\n", mkstemp_req.path); | |
| 375 | - Debug("[compile cache] writing cache for %s to temporary file %s [%d %d %d " | ||
| 420 | + Debug("[compile cache] writing cache for %s %s to temporary file %s [%d " | ||
| 421 | + "%d %d " | ||
| 376 | 422 | "%d %d]...", | |
| 423 | + type_name, | ||
| 377 | 424 | entry->source_filename, | |
| 378 | 425 | mkstemp_req.path, | |
| 379 | 426 | headers[kMagicNumberOffset], | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,10 +13,17 @@ | |||
| 13 | 13 | namespace node { | |
| 14 | 14 | class Environment; | |
| 15 | 15 | ||
| 16 | - // TODO(joyeecheung): move it into a CacheHandler class. | ||
| 16 | + #define CACHED_CODE_TYPES(V) \ | ||
| 17 | + V(kCommonJS, 0) \ | ||
| 18 | + V(kESM, 1) \ | ||
| 19 | + V(kStrippedTypeScript, 2) \ | ||
| 20 | + V(kTransformedTypeScript, 3) \ | ||
| 21 | + V(kTransformedTypeScriptWithSourceMaps, 4) | ||
| 22 | + | ||
| 17 | 23 | enum class CachedCodeType : uint8_t { | |
| 18 | - kCommonJS = 0, | ||
| 19 | - kESM, | ||
| 24 | + #define V(type, value) type = value, | ||
| 25 | + CACHED_CODE_TYPES(V) | ||
| 26 | + #undef V | ||
| 20 | 27 | }; | |
| 21 | 28 | ||
| 22 | 29 | struct CompileCacheEntry { | |
@@ -34,6 +41,7 @@ struct CompileCacheEntry { | |||
| 34 | 41 | // Copy the cache into a new store for V8 to consume. Caller takes | |
| 35 | 42 | // ownership. | |
| 36 | 43 | v8::ScriptCompiler::CachedData* CopyCache() const; | |
| 44 | + const char* type_name() const; | ||
| 37 | 45 | }; | |
| 38 | 46 | ||
| 39 | 47 | #define COMPILE_CACHE_STATUS(V) \ | |
@@ -70,6 +78,7 @@ class CompileCacheHandler { | |||
| 70 | 78 | void MaybeSave(CompileCacheEntry* entry, | |
| 71 | 79 | v8::Local<v8::Module> mod, | |
| 72 | 80 | bool rejected); | |
| 81 | + void MaybeSave(CompileCacheEntry* entry, std::string_view transpiled); | ||
| 73 | 82 | std::string_view cache_dir() { return compile_cache_dir_; } | |
| 74 | 83 | ||
| 75 | 84 | private: | |
| Back | FazBrowse Home | New Git URL |
0 commit comments