| 'use strict'; |
| |
| // Flags: --expose-internals |
| |
| // This file generates the code cache for builtin modules and |
| // writes them into static char arrays of a C++ file that can be |
| // compiled into the binary using the `--code-cache-path` option |
| // of `configure`. |
| |
| const { |
| getCodeCache, |
| getSource, |
| cachableBuiltins |
| } = require('internal/bootstrap/cache'); |
| |
| function hash(str) { |
| if (process.versions.openssl) { |
| return require('crypto').createHash('sha256').update(str).digest('hex'); |
| } |
| return ''; |
| } |
| |
| const fs = require('fs'); |
| |
| const resultPath = process.argv[2]; |
| if (!resultPath) { |
| console.error(`Usage: ${process.argv[0]} ${process.argv[1]}` + |
| 'path/to/node_code_cache.cc'); |
| process.exit(1); |
| } |
| |
| /** |
| * Format a number of a size in bytes into human-readable strings |
| * @param {number} num |
| * @return {string} |
| */ |
| function formatSize(num) { |
| if (num < 1024) { |
| return `${(num).toFixed(2)}B`; |
| } else if (num < 1024 ** 2) { |
| return `${(num / 1024).toFixed(2)}KB`; |
| } else if (num < 1024 ** 3) { |
| return `${(num / (1024 ** 2)).toFixed(2)}MB`; |
| } else { |
| return `${(num / (1024 ** 3)).toFixed(2)}GB`; |
| } |
| } |
| |
| /** |
| * Generates the source code of definitions of the char arrays |
| * that contains the code cache and the source code of the |
| * initializers of the code cache. |
| * |
| * @param {string} key ID of the builtin module |
| * @param {Buffer} cache Code cache of the builtin module |
| * @return { definition: string, initializer: string } |
| */ |
| function getInitalizer(key, cache) { |
| const defName = key.replace(/\//g, '_').replace(/-/g, '_'); |
| const definition = `static uint8_t ${defName}_raw[] = {\n` + |
| `${cache.join(',')}\n};`; |
| const source = getSource(key); |
| const sourceHash = hash(source); |
| const initializer = ` |
| v8::Local<v8::ArrayBuffer> ${defName}_ab = |
| v8::ArrayBuffer::New(isolate, ${defName}_raw, ${cache.length}); |
| v8::Local<v8::Uint8Array> ${defName}_array = |
| v8::Uint8Array::New(${defName}_ab, 0, ${cache.length}); |
| target->Set(context, |
| FIXED_ONE_BYTE_STRING(isolate, "${key}"), |
| ${defName}_array).FromJust(); |
| `; |
| const hashIntializer = ` |
| target->Set(context, |
| FIXED_ONE_BYTE_STRING(isolate, "${key}"), |
| OneByteString(isolate, "${sourceHash}")).FromJust(); |
| `; |
| return { |
| definition, initializer, hashIntializer, sourceHash |
| }; |
| } |
| |
| const cacheDefinitions = []; |
| const cacheInitializers = []; |
| const cacheHashInitializers = []; |
| let totalCacheSize = 0; |
| |
| |
| for (const key of cachableBuiltins) { |
| const cachedData = getCodeCache(key); |
| if (!cachedData.length) { |
| console.error(`Failed to generate code cache for '${key}'`); |
| process.exit(1); |
| } |
| |
| const length = cachedData.length; |
| totalCacheSize += length; |
| const { |
| definition, initializer, hashIntializer, sourceHash |
| } = getInitalizer(key, cachedData); |
| cacheDefinitions.push(definition); |
| cacheInitializers.push(initializer); |
| cacheHashInitializers.push(hashIntializer); |
| console.log(`Generated cache for '${key}', size = ${formatSize(length)}` + |
| `, hash = ${sourceHash}, total = ${formatSize(totalCacheSize)}`); |
| } |
| |
| const result = `#include "node.h" |
| #include "node_code_cache.h" |
| #include "v8.h" |
| #include "env.h" |
| #include "env-inl.h" |
| |
| // This file is generated by tools/generate_code_cache.js |
| // and is used when configure is run with \`--code-cache-path\` |
| |
| namespace node { |
| |
| ${cacheDefinitions.join('\n\n')} |
| |
| // The target here will be returned as \`internalBinding('code_cache')\` |
| void DefineCodeCache(Environment* env, v8::Local<v8::Object> target) { |
| v8::Isolate* isolate = env->isolate(); |
| v8::Local<v8::Context> context = env->context(); |
| ${cacheInitializers.join('\n')} |
| } |
| |
| // The target here will be returned as \`internalBinding('code_cache_hash')\` |
| void DefineCodeCacheHash(Environment* env, v8::Local<v8::Object> target) { |
| v8::Isolate* isolate = env->isolate(); |
| v8::Local<v8::Context> context = env->context(); |
| ${cacheHashInitializers.join('\n')} |
| } |
| |
| } // namespace node |
| `; |
| |
| fs.writeFileSync(resultPath, result); |
| console.log(`Generated code cache C++ file to ${resultPath}`); |