From 6c33033cbe2216ea57dd1225cdf1d66985aeec51 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 27 Feb 2024 12:10:02 +0100 Subject: [PATCH 01/13] feat: add ability to specify node::SnapshotFlags values MONGOSH-1605 (#54) --- resources/main-template.cc | 16 +++++++++++++++- src/index.ts | 9 +++++++++ test/index.ts | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/resources/main-template.cc b/resources/main-template.cc index b04c19b..a45b277 100644 --- a/resources/main-template.cc +++ b/resources/main-template.cc @@ -17,6 +17,7 @@ #include #include #endif +#include // injected code may refer to std::underlying_type using namespace node; using namespace v8; @@ -33,6 +34,11 @@ using namespace v8; #define NODE_VERSION_SUPPORTS_EMBEDDER_SNAPSHOT 1 #endif +// Snapshot config is supported since https://github.com/nodejs/node/pull/50453 +#if NODE_VERSION_AT_LEAST(21, 6, 0) && !defined(BOXEDNODE_SNAPSHOT_CONFIG_FLAGS) +#define BOXEDNODE_SNAPSHOT_CONFIG_FLAGS (SnapshotFlags::kWithoutCodeCache) +#endif + // 18.1.0 is the current minimum version that has https://github.com/nodejs/node/pull/42809, // which introduced crashes when using workers, and later 18.9.0 is the current // minimum version to contain https://github.com/nodejs/node/pull/44252, which @@ -167,7 +173,15 @@ static int RunNodeInstance(MultiIsolatePlatform* platform, int exit_code = 0; std::vector errors; std::unique_ptr setup = - CommonEnvironmentSetup::CreateForSnapshotting(platform, &errors, args, exec_args); + CommonEnvironmentSetup::CreateForSnapshotting( + platform, + &errors, + args, + exec_args +#ifdef BOXEDNODE_SNAPSHOT_CONFIG_FLAGS + , SnapshotConfig { BOXEDNODE_SNAPSHOT_CONFIG_FLAGS, std::nullopt } +#endif + ); Isolate* isolate = setup->isolate(); diff --git a/src/index.ts b/src/index.ts index b9b4d07..59f0ab6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -275,6 +275,7 @@ type CompilationOptions = { useLegacyDefaultUvLoop?: boolean; useCodeCache?: boolean, useNodeSnapshot?: boolean, + nodeSnapshotConfigFlags?: string[], // e.g. 'WithoutCodeCache' executableMetadata?: ExecutableMetadata, preCompileHook?: (nodeSourceTree: string, options: CompilationOptions) => void | Promise } @@ -421,6 +422,14 @@ async function compileJSFileAsBinaryImpl (options: CompilationOptions, logger: L if (snapshotMode === 'consume') { mainSource = `#define BOXEDNODE_CONSUME_SNAPSHOT 1\n${mainSource}`; } + if (options.nodeSnapshotConfigFlags) { + const flags = [ + '0', + ...options.nodeSnapshotConfigFlags.map(flag => + `static_cast::type>(SnapshotFlags::k${flag})`) + ].join(' | '); + mainSource = `#define BOXEDNODE_SNAPSHOT_CONFIG_FLAGS (static_cast(${flags}))\n${mainSource}`; + } await fs.writeFile(path.join(nodeSourcePath, 'src', 'node_main.cc'), mainSource); logger.stepCompleted(); diff --git a/test/index.ts b/test/index.ts index 2849974..725af8c 100644 --- a/test/index.ts +++ b/test/index.ts @@ -217,10 +217,11 @@ describe('basic functionality', () => { it('works with snapshot support', async function () { this.timeout(2 * 60 * 60 * 1000); // 2 hours await compileJSFileAsBinary({ - nodeVersionRange: 'v21.0.0-nightly20230801d396a041f7', + nodeVersionRange: '^21.6.2', sourceFile: path.resolve(__dirname, 'resources/snapshot-echo-args.js'), targetFile: path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), useNodeSnapshot: true, + nodeSnapshotConfigFlags: ['WithoutCodeCache'], // the nightly path name is too long for Windows... tmpdir: process.platform === 'win32' ? path.join(os.tmpdir(), 'bn') : undefined }); From dcd959b7a79ffa8f75f96d891c3ad921448c3b94 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 27 Mar 2024 14:46:21 +0100 Subject: [PATCH 02/13] fix(ci): re-enable CodeQL for C++ COMPASS-7540 (#55) --- .github/workflows/codeql.yml | 5 ++--- .gitignore | 1 + resources/main-template.cc | 2 +- test/compile-main-template-only.sh | 30 ++++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100755 test/compile-main-template-only.sh diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index eac4694..574fcf1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -36,8 +36,7 @@ jobs: matrix: language: - 'javascript' - # TODO: https://jira.mongodb.org/browse/COMPASS-7540, enable the cpp analysis. - # - 'cpp' + - 'cpp' steps: - name: Checkout repository @@ -78,7 +77,7 @@ jobs: - name: Build cpp if: matrix.language == 'cpp' run: | - node bin/boxednode.js -s test/resources/example.js -t example + ./test/compile-main-template-only.sh - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore index aba52b9..b1a3b11 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ tmp/ .esm-wrapper.mjs /lib/ package-lock.json +main-template-build diff --git a/resources/main-template.cc b/resources/main-template.cc index a45b277..6aa297a 100644 --- a/resources/main-template.cc +++ b/resources/main-template.cc @@ -35,7 +35,7 @@ using namespace v8; #endif // Snapshot config is supported since https://github.com/nodejs/node/pull/50453 -#if NODE_VERSION_AT_LEAST(21, 6, 0) && !defined(BOXEDNODE_SNAPSHOT_CONFIG_FLAGS) +#if NODE_VERSION_AT_LEAST(20, 12, 0) && !defined(BOXEDNODE_SNAPSHOT_CONFIG_FLAGS) #define BOXEDNODE_SNAPSHOT_CONFIG_FLAGS (SnapshotFlags::kWithoutCodeCache) #endif diff --git a/test/compile-main-template-only.sh b/test/compile-main-template-only.sh new file mode 100755 index 0000000..7e4316a --- /dev/null +++ b/test/compile-main-template-only.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# script to only build the code in resources/ +# for CodeQL testing + +set -e +set -x +cd "$(dirname $0)/.." +if [ ! -e main-template-build ]; then + mkdir main-template-build + pushd main-template-build + curl -O https://nodejs.org/dist/v20.12.0/node-v20.12.0.tar.xz + tar --strip-components=1 -xf node-*.tar.xz + popd +fi + +g++ \ + -Imain-template-build/src \ + -Imain-template-build/deps/v8/include \ + -Imain-template-build/deps/uv/include \ + -DREPLACE_DECLARE_LINKED_MODULES= \ + -DREPLACE_DEFINE_LINKED_MODULES= \ + -DREPLACE_WITH_ENTRY_POINT='"placeholder"' \ + -DBOXEDNODE_CODE_CACHE_MODE='"placeholder"' \ + -DREPLACE_WITH_MAIN_SCRIPT_SOURCE_GETTER= \ + -fPIC -shared \ + -o main-template-build/out.so \ + -include resources/add-node_api.h \ + -include resources/add-node.h \ + resources/main-template.cc From 115008f92ec1348b6b54447c2759f98f84ab62d0 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 11 Apr 2024 15:09:39 +0200 Subject: [PATCH 03/13] fix: work around Node.js April 2024 security release (#56) https://github.com/nodejs/node/commit/9095c914ed8467cf16f077a3fac20b1f1e89bbe4 disallowed spawning `.bat` files directly, without running them inside of a shell such as `cmd`. Boxednode needs to be adjusted for this. --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 59f0ab6..cfad964 100644 --- a/src/index.ts +++ b/src/index.ts @@ -253,7 +253,7 @@ async function compileNode ( for (const module of linkedJSModules) { vcbuildArgs.push('link-module', module); } - await spawnBuildCommand(['.\\vcbuild.bat', ...vcbuildArgs], options); + await spawnBuildCommand(['cmd', '/c', '.\\vcbuild.bat', ...vcbuildArgs], options); return path.join(sourcePath, 'Release', 'node.exe'); } From b2cb73fc6dad12f410805ecef911bca8096454a8 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 11 Apr 2024 15:20:15 +0200 Subject: [PATCH 04/13] 2.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca13efb..62c3c81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boxednode", - "version": "2.3.0", + "version": "2.3.1", "description": "Create a shippable binary from a JS file", "main": "lib/index.js", "exports": { From cc38b50bd604f16dd0ffbe4fe3ed5659b4023593 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 11 Apr 2024 15:23:12 +0200 Subject: [PATCH 05/13] fix: add main-template-build to npmignore (#57) --- .npmignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.npmignore b/.npmignore index 0c615a3..376940d 100644 --- a/.npmignore +++ b/.npmignore @@ -6,3 +6,4 @@ test/ .evergreen.yml tsconfig.json .eslintrc +main-template-build/ From cd1e937b239760f2ca471f3fe5b6717501e2e45c Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 11 Apr 2024 15:23:54 +0200 Subject: [PATCH 06/13] 2.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 62c3c81..9361165 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boxednode", - "version": "2.3.1", + "version": "2.3.2", "description": "Create a shippable binary from a JS file", "main": "lib/index.js", "exports": { From 6d28f9fd547978d2a4f8ef1669857800f6fc88fe Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 11 Apr 2024 15:26:38 +0200 Subject: [PATCH 07/13] 2.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9361165..072f4d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boxednode", - "version": "2.3.2", + "version": "2.4.1", "description": "Create a shippable binary from a JS file", "main": "lib/index.js", "exports": { From ac136728581f5008e58c0798a9eeb97c6b836265 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 15 Apr 2024 16:05:01 +0200 Subject: [PATCH 08/13] feat: enable optionally enabling/disabling blob compression (#58) While blobs such as startup snapshots (40MB in the case of mongosh) can be quite large and compressing them saves binary size, decompressing them also costs non-trivial startup time. We make compression optional in this commit so that we can turn it off in mongosh. --- bin/boxednode.js | 3 ++- src/helpers.ts | 34 ++++++++++++++++++++++---------- src/index.ts | 11 ++++++++--- test/index.ts | 51 +++++++++++++++++++++++++----------------------- 4 files changed, 61 insertions(+), 38 deletions(-) diff --git a/bin/boxednode.js b/bin/boxednode.js index b309214..7f7804c 100755 --- a/bin/boxednode.js +++ b/bin/boxednode.js @@ -54,7 +54,8 @@ const argv = require('yargs') namespace: argv.N, useLegacyDefaultUvLoop: argv.useLegacyDefaultUvLoop, useCodeCache: argv.H, - useNodeSnapshot: argv.S + useNodeSnapshot: argv.S, + compressBlobs: argv.Z }); } catch (err) { console.error(err); diff --git a/src/helpers.ts b/src/helpers.ts index 2fddc6c..cee4fc5 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -107,6 +107,21 @@ export function createCppJsStringDefinition (fnName: string, source: string): st `; } +export async function createUncompressedBlobDefinition (fnName: string, source: Uint8Array): Promise { + return ` + static const uint8_t ${fnName}_source_[] = { + ${Uint8Array.prototype.toString.call(source) || '0'} + }; + + std::vector ${fnName}Vector() { + return std::vector( + reinterpret_cast(&${fnName}_source_[0]), + reinterpret_cast(&${fnName}_source_[${source.length}])); + } + + ${blobTypedArrayAccessors(fnName, source.length)}`; +} + export async function createCompressedBlobDefinition (fnName: string, source: Uint8Array): Promise { const compressed = await promisify(zlib.brotliCompress)(source, { params: { @@ -133,13 +148,6 @@ export async function createCompressedBlobDefinition (fnName: string, source: Ui assert(decoded_size == ${source.length}); } - std::string ${fnName}() { - ${source.length === 0 ? 'return {};' : ` - std::string dst(${source.length}, 0); - ${fnName}_Read(&dst[0]); - return dst;`} - } - std::vector ${fnName}Vector() { ${source.length === 0 ? 'return {};' : ` std::vector dst(${source.length}); @@ -147,19 +155,25 @@ export async function createCompressedBlobDefinition (fnName: string, source: Ui return dst;`} } + ${blobTypedArrayAccessors(fnName, source.length)} + `; +} + +function blobTypedArrayAccessors (fnName: string, sourceLength: number): string { + return ` std::shared_ptr ${fnName}BackingStore() { - std::string* str = new std::string(std::move(${fnName}())); + std::vector* str = new std::vector(std::move(${fnName}Vector())); return v8::SharedArrayBuffer::NewBackingStore( &str->front(), str->size(), [](void*, size_t, void* deleter_data) { - delete static_cast(deleter_data); + delete static_cast*>(deleter_data); }, static_cast(str)); } v8::Local ${fnName}Buffer(v8::Isolate* isolate) { - ${source.length === 0 ? ` + ${sourceLength === 0 ? ` auto array_buffer = v8::SharedArrayBuffer::New(isolate, 0); ` : ` auto array_buffer = v8::SharedArrayBuffer::New(isolate, ${fnName}BackingStore()); diff --git a/src/index.ts b/src/index.ts index cfad964..2a9b379 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ import { promisify } from 'util'; import { promises as fs, createReadStream, createWriteStream } from 'fs'; import { AddonConfig, loadGYPConfig, storeGYPConfig, modifyAddonGyp } from './native-addons'; import { ExecutableMetadata, generateRCFile } from './executable-metadata'; -import { spawnBuildCommand, ProcessEnv, pipeline, createCppJsStringDefinition, createCompressedBlobDefinition } from './helpers'; +import { spawnBuildCommand, ProcessEnv, pipeline, createCppJsStringDefinition, createCompressedBlobDefinition, createUncompressedBlobDefinition } from './helpers'; import { Readable } from 'stream'; import nv from '@pkgjs/nv'; import { fileURLToPath, URL } from 'url'; @@ -275,6 +275,7 @@ type CompilationOptions = { useLegacyDefaultUvLoop?: boolean; useCodeCache?: boolean, useNodeSnapshot?: boolean, + compressBlobs?: boolean, nodeSnapshotConfigFlags?: string[], // e.g. 'WithoutCodeCache' executableMetadata?: ExecutableMetadata, preCompileHook?: (nodeSourceTree: string, options: CompilationOptions) => void | Promise @@ -387,6 +388,10 @@ async function compileJSFileAsBinaryImpl (options: CompilationOptions, logger: L logger.stepCompleted(); } + const createBlobDefinition = options.compressBlobs + ? createCompressedBlobDefinition + : createUncompressedBlobDefinition; + async function writeMainFileAndCompile ({ codeCacheBlob = new Uint8Array(0), codeCacheMode = 'ignore', @@ -409,8 +414,8 @@ async function compileJSFileAsBinaryImpl (options: CompilationOptions, logger: L registerFunctions.map((fn) => `${fn},`).join('')); mainSource = mainSource.replace(/\bREPLACE_WITH_MAIN_SCRIPT_SOURCE_GETTER\b/g, createCppJsStringDefinition('GetBoxednodeMainScriptSource', snapshotMode !== 'consume' ? jsMainSource : '') + '\n' + - await createCompressedBlobDefinition('GetBoxednodeCodeCache', codeCacheBlob) + '\n' + - await createCompressedBlobDefinition('GetBoxednodeSnapshotBlob', snapshotBlob)); + await createBlobDefinition('GetBoxednodeCodeCache', codeCacheBlob) + '\n' + + await createBlobDefinition('GetBoxednodeSnapshotBlob', snapshotBlob)); mainSource = mainSource.replace(/\bBOXEDNODE_CODE_CACHE_MODE\b/g, JSON.stringify(codeCacheMode)); if (options.useLegacyDefaultUvLoop) { diff --git a/test/index.ts b/test/index.ts index 725af8c..723db64 100644 --- a/test/index.ts +++ b/test/index.ts @@ -214,30 +214,33 @@ describe('basic functionality', () => { } }); - it('works with snapshot support', async function () { - this.timeout(2 * 60 * 60 * 1000); // 2 hours - await compileJSFileAsBinary({ - nodeVersionRange: '^21.6.2', - sourceFile: path.resolve(__dirname, 'resources/snapshot-echo-args.js'), - targetFile: path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), - useNodeSnapshot: true, - nodeSnapshotConfigFlags: ['WithoutCodeCache'], - // the nightly path name is too long for Windows... - tmpdir: process.platform === 'win32' ? path.join(os.tmpdir(), 'bn') : undefined - }); + for (const compressBlobs of [false, true]) { + it(`works with snapshot support (compressBlobs = ${compressBlobs})`, async function () { + this.timeout(2 * 60 * 60 * 1000); // 2 hours + await compileJSFileAsBinary({ + nodeVersionRange: '^21.6.2', + sourceFile: path.resolve(__dirname, 'resources/snapshot-echo-args.js'), + targetFile: path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), + useNodeSnapshot: true, + compressBlobs, + nodeSnapshotConfigFlags: ['WithoutCodeCache'], + // the nightly path name is too long for Windows... + tmpdir: process.platform === 'win32' ? path.join(os.tmpdir(), 'bn') : undefined + }); - { - const { stdout } = await execFile( - path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), ['a', 'b', 'c'], - { encoding: 'utf8' }); - const { currentArgv, originalArgv, timingData } = JSON.parse(stdout); - assert(currentArgv[0].includes('snapshot-echo-args')); - assert(currentArgv[1].includes('snapshot-echo-args')); - assert.deepStrictEqual(currentArgv.slice(2), ['a', 'b', 'c']); - assert.strictEqual(originalArgv.length, 2); // [execPath, execPath] - assert.strictEqual(timingData[0][0], 'Node.js Instance'); - assert.strictEqual(timingData[0][1], 'Process initialization'); - } - }); + { + const { stdout } = await execFile( + path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), ['a', 'b', 'c'], + { encoding: 'utf8' }); + const { currentArgv, originalArgv, timingData } = JSON.parse(stdout); + assert(currentArgv[0].includes('snapshot-echo-args')); + assert(currentArgv[1].includes('snapshot-echo-args')); + assert.deepStrictEqual(currentArgv.slice(2), ['a', 'b', 'c']); + assert.strictEqual(originalArgv.length, 2); // [execPath, execPath] + assert.strictEqual(timingData[0][0], 'Node.js Instance'); + assert.strictEqual(timingData[0][1], 'Process initialization'); + } + }); + } }); }); From fd3cad12dd69c64d182c2435a0db4d605a9d52f7 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 15 Apr 2024 16:06:08 +0200 Subject: [PATCH 09/13] 2.4.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 072f4d8..9d04c2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boxednode", - "version": "2.4.1", + "version": "2.4.2", "description": "Create a shippable binary from a JS file", "main": "lib/index.js", "exports": { From 6ff72363d47b9269dfeff8d941a3362b1eb65060 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 15 May 2024 18:58:31 +0200 Subject: [PATCH 10/13] fix: remove heap allocation for startup snapshot where possible MONGOSH-1771 (#60) --- .evergreen.yml | 4 ++-- .github/workflows/nodejs.yml | 2 +- resources/main-template.cc | 25 +++++++++++++++++++++---- src/helpers.ts | 17 +++++++++++++++++ test/index.ts | 2 +- 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/.evergreen.yml b/.evergreen.yml index 4f13b43..a0edaa6 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -14,7 +14,7 @@ functions: set -e set -x - export NODE_VERSION=20.5.0 + export NODE_VERSION=20.13.0 bash .evergreen/install-node.sh install: - command: shell.exec @@ -106,7 +106,7 @@ tasks: - func: install - func: test vars: - node_version: "20.5.0" + node_version: "20.13.0" - name: check commands: - func: checkout diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index bc4e2ce..293c59b 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - node-version: [14.x, 16.x, 18.x, 19.x] + node-version: [14.x, 16.x, 18.x, 20.x] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/resources/main-template.cc b/resources/main-template.cc index 6aa297a..c63b118 100644 --- a/resources/main-template.cc +++ b/resources/main-template.cc @@ -18,6 +18,7 @@ #include #endif #include // injected code may refer to std::underlying_type +#include using namespace node; using namespace v8; @@ -34,6 +35,12 @@ using namespace v8; #define NODE_VERSION_SUPPORTS_EMBEDDER_SNAPSHOT 1 #endif +// 20.13.0 has https://github.com/nodejs/node/pull/52595 for better startup snapshot +// initialization performance. +#if NODE_VERSION_AT_LEAST(20, 13, 0) +#define NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT 1 +#endif + // Snapshot config is supported since https://github.com/nodejs/node/pull/50453 #if NODE_VERSION_AT_LEAST(20, 12, 0) && !defined(BOXEDNODE_SNAPSHOT_CONFIG_FLAGS) #define BOXEDNODE_SNAPSHOT_CONFIG_FLAGS (SnapshotFlags::kWithoutCodeCache) @@ -81,6 +88,9 @@ void MarkTime(const char* category, const char* label) { Local GetBoxednodeMainScriptSource(Isolate* isolate); Local GetBoxednodeCodeCacheBuffer(Isolate* isolate); std::vector GetBoxednodeSnapshotBlobVector(); +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT +std::optional GetBoxednodeSnapshotBlobSV(); +#endif void GetTimingData(const FunctionCallbackInfo& info) { Isolate* isolate = info.GetIsolate(); @@ -230,11 +240,18 @@ static int RunNodeInstance(MultiIsolatePlatform* platform, ArrayBufferAllocator::Create(); #ifdef BOXEDNODE_CONSUME_SNAPSHOT - std::vector snapshot_blob_vec = boxednode::GetBoxednodeSnapshotBlobVector(); - boxednode::MarkTime("Node.js Instance", "Decoded snapshot"); assert(EmbedderSnapshotData::CanUseCustomSnapshotPerIsolate()); - node::EmbedderSnapshotData::Pointer snapshot_blob = - EmbedderSnapshotData::FromBlob(snapshot_blob_vec); + node::EmbedderSnapshotData::Pointer snapshot_blob; +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT + if (const auto snapshot_blob_sv = boxednode::GetBoxednodeSnapshotBlobSV()) { + snapshot_blob = EmbedderSnapshotData::FromBlob(snapshot_blob_sv.value()); + } +#endif + if (!snapshot_blob) { + std::vector snapshot_blob_vec = boxednode::GetBoxednodeSnapshotBlobVector(); + boxednode::MarkTime("Node.js Instance", "Decoded snapshot"); + snapshot_blob = EmbedderSnapshotData::FromBlob(snapshot_blob_vec); + } boxednode::MarkTime("Node.js Instance", "Read snapshot"); Isolate* isolate = NewIsolate(allocator, loop, platform, snapshot_blob.get()); #elif NODE_VERSION_AT_LEAST(14, 0, 0) diff --git a/src/helpers.ts b/src/helpers.ts index cee4fc5..2b14801 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -113,6 +113,17 @@ export async function createUncompressedBlobDefinition (fnName: string, source: ${Uint8Array.prototype.toString.call(source) || '0'} }; +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT + std::optional ${fnName}SV() { + return { + { + reinterpret_cast(&${fnName}_source_[0]), + ${source.length} + } + }; + } +#endif + std::vector ${fnName}Vector() { return std::vector( reinterpret_cast(&${fnName}_source_[0]), @@ -155,6 +166,12 @@ export async function createCompressedBlobDefinition (fnName: string, source: Ui return dst;`} } +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT + std::optional ${fnName}SV() { + return {}; + } +#endif + ${blobTypedArrayAccessors(fnName, source.length)} `; } diff --git a/test/index.ts b/test/index.ts index 723db64..f0fafbf 100644 --- a/test/index.ts +++ b/test/index.ts @@ -218,7 +218,7 @@ describe('basic functionality', () => { it(`works with snapshot support (compressBlobs = ${compressBlobs})`, async function () { this.timeout(2 * 60 * 60 * 1000); // 2 hours await compileJSFileAsBinary({ - nodeVersionRange: '^21.6.2', + nodeVersionRange: '^20.13.0', sourceFile: path.resolve(__dirname, 'resources/snapshot-echo-args.js'), targetFile: path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), useNodeSnapshot: true, From 1a70fc4fea67f3fe6585046a2c2d1505b5ffba3a Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 15 May 2024 18:59:09 +0200 Subject: [PATCH 11/13] 2.4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d04c2f..e339bcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boxednode", - "version": "2.4.2", + "version": "2.4.3", "description": "Create a shippable binary from a JS file", "main": "lib/index.js", "exports": { From 5c71a18ed6d227358d46f1153e84db617fc6cf71 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 5 Sep 2024 10:36:19 +0200 Subject: [PATCH 12/13] fix: fix typo in --fully-static support code (#59) --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 2a9b379..c7c96c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -224,7 +224,7 @@ async function compileNode ( } let source = await fs.readFile(target, 'utf8'); source = source.replace(/-static/g, ''); - await fs.writeFile(target, 'utf8'); + await fs.writeFile(target, source); } } From ea49575d04cab250e39974f3b7de40bec200e98a Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 5 Sep 2024 10:36:54 +0200 Subject: [PATCH 13/13] 2.4.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e339bcf..7d7f769 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boxednode", - "version": "2.4.3", + "version": "2.4.4", "description": "Create a shippable binary from a JS file", "main": "lib/index.js", "exports": {