Skip to content

Commit

Permalink
sea: generate code cache with deserialized isolate
Browse files Browse the repository at this point in the history
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: #49226
Refs: nodejs/node-v8#252
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
  • Loading branch information
joyeecheung authored and UlisesGascon committed Sep 10, 2023
1 parent 55d6649 commit d7ff78b
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 8 deletions.
21 changes: 13 additions & 8 deletions src/node_sea.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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{
Expand Down
Original file line number Diff line number Diff line change
@@ -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');
}

0 comments on commit d7ff78b

Please sign in to comment.