sea: generate code cache with deserialized isolate

V8 now requires code cache to be compiled from an isolate with the
same RO space layout as the one that's going to deserialize the
cache, so for a binary built with snapshot, we need to compile
the code cache using a deserialized isolate.

Drive-by: ignore "useCodeCache" when "useSnapshot" is true because
the compilation would've been done during build time anyway in
that case, and print a warning for it.

PR-URL: https://github.com/nodejs/node/pull/49226
Refs: https://github.com/nodejs/node-v8/issues/252
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
Joyee Cheung 2023-08-18 14:16:55 +02:00 committed by Node.js GitHub Bot
parent f6f1131096
commit 5c9daf4583
2 changed files with 76 additions and 8 deletions

View File

@ -411,7 +411,7 @@ ExitCode GenerateSnapshotForSEA(const SeaConfig& config,
std::optional<std::string> GenerateCodeCache(std::string_view main_path,
std::string_view main_script) {
RAIIIsolate raii_isolate;
RAIIIsolate raii_isolate(SnapshotBuilder::GetEmbeddedSnapshotData());
Isolate* isolate = raii_isolate.get();
HandleScope handle_scope(isolate);
@ -489,14 +489,19 @@ ExitCode GenerateSingleExecutableBlob(
std::optional<std::string_view> optional_sv_code_cache;
std::string code_cache;
if (static_cast<bool>(config.flags & SeaFlags::kUseCodeCache)) {
std::optional<std::string> optional_code_cache =
GenerateCodeCache(config.main_path, main_script);
if (!optional_code_cache.has_value()) {
FPrintF(stderr, "Cannot generate V8 code cache\n");
return ExitCode::kGenericUserError;
if (builds_snapshot_from_main) {
FPrintF(stderr,
"\"useCodeCache\" is redundant when \"useSnapshot\" is true\n");
} else {
std::optional<std::string> optional_code_cache =
GenerateCodeCache(config.main_path, main_script);
if (!optional_code_cache.has_value()) {
FPrintF(stderr, "Cannot generate V8 code cache\n");
return ExitCode::kGenericUserError;
}
code_cache = optional_code_cache.value();
optional_sv_code_cache = code_cache;
}
code_cache = optional_code_cache.value();
optional_sv_code_cache = code_cache;
}
SeaResource sea{

View File

@ -0,0 +1,63 @@
'use strict';
require('../common');
const {
injectAndCodeSign,
skipIfSingleExecutableIsNotSupported,
} = require('../common/sea');
skipIfSingleExecutableIsNotSupported();
// This tests "useCodeCache" is ignored when "useSnapshot" is true.
const tmpdir = require('../common/tmpdir');
const { copyFileSync, writeFileSync, existsSync } = require('fs');
const { spawnSync } = require('child_process');
const { join } = require('path');
const assert = require('assert');
const configFile = join(tmpdir.path, 'sea-config.json');
const seaPrepBlob = join(tmpdir.path, 'sea-prep.blob');
const outputFile = join(tmpdir.path, process.platform === 'win32' ? 'sea.exe' : 'sea');
{
tmpdir.refresh();
const code = `
const {
setDeserializeMainFunction,
} = require('v8').startupSnapshot;
setDeserializeMainFunction(() => {
console.log('Hello from snapshot');
});
`;
writeFileSync(join(tmpdir.path, 'snapshot.js'), code, 'utf-8');
writeFileSync(configFile, `
{
"main": "snapshot.js",
"output": "sea-prep.blob",
"useSnapshot": true,
"useCodeCache": true
}
`);
let child = spawnSync(
process.execPath,
['--experimental-sea-config', 'sea-config.json'],
{
cwd: tmpdir.path
});
assert.match(
child.stderr.toString(),
/"useCodeCache" is redundant when "useSnapshot" is true/);
assert(existsSync(seaPrepBlob));
copyFileSync(process.execPath, outputFile);
injectAndCodeSign(outputFile, seaPrepBlob);
child = spawnSync(outputFile);
assert.strictEqual(child.stdout.toString().trim(), 'Hello from snapshot');
}