mirror of
https://github.com/nodejs/node.git
synced 2024-11-30 15:30:56 +01:00
bd765d61d7
This patch refactors out a part of NativeModule.prototype.compile (in JS land) into a C++ NativeModule class, this enables a couple of possibilities: 1. By moving the code to the C++ land, we have more opportunity to specialize the compilation process of the native modules (e.g. compilation options, code cache) that is orthogonal to how user land modules are compiled 2. We can reuse the code to compile bootstrappers and context fixers and enable them to be compiled with the code cache later, since they are not loaded by NativeModule in the JS land their caching must be done in C++. 3. Since there is no need to pass the static data to JS for compilation anymore, this enables us to use (std::map<std::string, const char*>) in the generated node_code_cache.cc and node_javascript.cc later, and scope every actual access to the source of native modules to a std::map lookup instead of a lookup on a v8::Object in dictionary mode. This patch also refactor the code cache generator and tests a bit and trace the `withCodeCache` and `withoutCodeCache` in a Set instead of an Array, and makes sure that all the cachable builtins are tested. PR-URL: https://github.com/nodejs/node/pull/24221 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
142 lines
4.1 KiB
JavaScript
142 lines
4.1 KiB
JavaScript
'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 {
|
|
getSource,
|
|
getCodeCache,
|
|
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')}
|
|
|
|
const bool native_module_has_code_cache = true;
|
|
|
|
// 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}`);
|