From 5c9daf458327aacd9db463807f991752ca4e4f3f Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 18 Aug 2023 14:16:55 +0200 Subject: [PATCH] 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 Reviewed-By: Yagiz Nizipli --- src/node_sea.cc | 21 ++++--- ...ble-application-snapshot-and-code-cache.js | 63 +++++++++++++++++++ 2 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 test/sequential/test-single-executable-application-snapshot-and-code-cache.js diff --git a/src/node_sea.cc b/src/node_sea.cc index a8dbfeaa42..521f2f670b 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -411,7 +411,7 @@ ExitCode GenerateSnapshotForSEA(const SeaConfig& config, std::optional 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 optional_sv_code_cache; std::string code_cache; if (static_cast(config.flags & SeaFlags::kUseCodeCache)) { - std::optional 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 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{ diff --git a/test/sequential/test-single-executable-application-snapshot-and-code-cache.js b/test/sequential/test-single-executable-application-snapshot-and-code-cache.js new file mode 100644 index 0000000000..66012e38a4 --- /dev/null +++ b/test/sequential/test-single-executable-application-snapshot-and-code-cache.js @@ -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'); +}