From d4e9ec6185694e2247ed6a517e0b688e151e9ee9 Mon Sep 17 00:00:00 2001 From: Philipp Dunkel Date: Mon, 27 Nov 2023 10:47:11 +0000 Subject: [PATCH 1/2] sea: add ability to embedd auxiliary data asset for use with sea When bundling code into a single executable application sometimes it is necessary to include non-code assets. While this is possible to do as base64 encoded blobs in the code itself, adding these assets as a separate resource makes things a lot smaller. --- lib/internal/util.js | 3 +++ lib/util.js | 7 +++++++ src/node_sea.cc | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/lib/internal/util.js b/lib/internal/util.js index 80ce774a211644..dfa737695faddd 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -54,6 +54,8 @@ const { overrideStackTrace, } = require('internal/errors'); const { signals } = internalBinding('constants').os; +const { getEmbeddedData } = internalBinding('sea'); + const { isArrayBufferDetached: _isArrayBufferDetached, guessHandleType: _guessHandleType, @@ -874,6 +876,7 @@ class WeakReference { } module.exports = { + getEmbeddedData, getLazy, assertCrypto, cachedResult, diff --git a/lib/util.js b/lib/util.js index 9ddb332f866355..a3fc337e15c68b 100644 --- a/lib/util.js +++ b/lib/util.js @@ -77,6 +77,7 @@ const { promisify, toUSVString, defineLazyProperties, + getEmbeddedData } = require('internal/util'); let abortController; @@ -441,3 +442,9 @@ defineLazyProperties( 'internal/mime', ['MIMEType', 'MIMEParams'], ); + +defineLazyProperties( + module.exports, + 'internal/util', + ['getEmbeddedData'] +); diff --git a/src/node_sea.cc b/src/node_sea.cc index d1ab5051032d76..f388e5005f04e7 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -257,6 +257,41 @@ void GetCodeCache(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(data_view); } + +#define POSTJECT_SENTINEL_EMBED "NODE_EMBED_fce680ab2cc467b6e072b8b5df1996b2" +static inline bool hasEmbeddedData() { + static const volatile char* sentinel = POSTJECT_SENTINEL_EMBED ":0"; + return sentinel[sizeof(POSTJECT_SENTINEL_EMBED)] == '1'; +} +#undef POSTJECT_SENTINEL_EMBED +void GetEmbeddedData(const FunctionCallbackInfo &args) { + if (!hasEmbeddedData()) { + return; + } + + Isolate* isolate = args.GetIsolate(); + size_t size = 0; + #ifdef __APPLE__ + postject_options options; + postject_options_init(&options); + options.macho_segment_name = "NODE_SEA"; + const void* data = postject_find_resource("NODE_EMBEDDED_DATA", &size, &options); + #else + const void* data = postject_find_resource("NODE_EMBEDDED_DATA", &size, nullptr); + #endif + + std::shared_ptr backing_store = ArrayBuffer::NewBackingStore( + const_cast(static_cast(data)), + size, + [](void* /* data */, size_t /* length */, void* /* deleter_data */) { + // The code cache data blob is not freed here because it is a static + // blob which is not allocated by the BackingStore allocator. + }, + nullptr); + Local array_buffer = ArrayBuffer::New(isolate, backing_store); + args.GetReturnValue().Set(array_buffer); +} + void GetCodePath(const FunctionCallbackInfo& args) { DCHECK(IsSingleExecutable()); @@ -558,6 +593,7 @@ void Initialize(Local target, IsExperimentalSeaWarningNeeded); SetMethod(context, target, "getCodePath", GetCodePath); SetMethod(context, target, "getCodeCache", GetCodeCache); + SetMethod(context, target, "getEmbeddedData", GetEmbeddedData); } void RegisterExternalReferences(ExternalReferenceRegistry* registry) { @@ -565,6 +601,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(IsExperimentalSeaWarningNeeded); registry->Register(GetCodePath); registry->Register(GetCodeCache); + registry->Register(GetEmbeddedData); } } // namespace sea From d8e32a9676da60f588ff117ac9b2ad0d73887041 Mon Sep 17 00:00:00 2001 From: Philipp Dunkel Date: Mon, 27 Nov 2023 14:32:35 +0000 Subject: [PATCH 2/2] linting/formatting --- lib/util.js | 9 ++------- src/node_sea.cc | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/util.js b/lib/util.js index a3fc337e15c68b..f83c6649db179a 100644 --- a/lib/util.js +++ b/lib/util.js @@ -77,7 +77,7 @@ const { promisify, toUSVString, defineLazyProperties, - getEmbeddedData + getEmbeddedData, } = require('internal/util'); let abortController; @@ -385,6 +385,7 @@ module.exports = { formatWithOptions, getSystemErrorMap, getSystemErrorName, + getEmbeddedData, inherits, inspect, isArray: ArrayIsArray, @@ -442,9 +443,3 @@ defineLazyProperties( 'internal/mime', ['MIMEType', 'MIMEParams'], ); - -defineLazyProperties( - module.exports, - 'internal/util', - ['getEmbeddedData'] -); diff --git a/src/node_sea.cc b/src/node_sea.cc index f388e5005f04e7..8efc7c09a20202 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -257,30 +257,31 @@ void GetCodeCache(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(data_view); } - #define POSTJECT_SENTINEL_EMBED "NODE_EMBED_fce680ab2cc467b6e072b8b5df1996b2" static inline bool hasEmbeddedData() { static const volatile char* sentinel = POSTJECT_SENTINEL_EMBED ":0"; return sentinel[sizeof(POSTJECT_SENTINEL_EMBED)] == '1'; } #undef POSTJECT_SENTINEL_EMBED -void GetEmbeddedData(const FunctionCallbackInfo &args) { +void GetEmbeddedData(const FunctionCallbackInfo& args) { if (!hasEmbeddedData()) { return; } Isolate* isolate = args.GetIsolate(); size_t size = 0; - #ifdef __APPLE__ - postject_options options; - postject_options_init(&options); - options.macho_segment_name = "NODE_SEA"; - const void* data = postject_find_resource("NODE_EMBEDDED_DATA", &size, &options); - #else - const void* data = postject_find_resource("NODE_EMBEDDED_DATA", &size, nullptr); - #endif +#ifdef __APPLE__ + postject_options options; + postject_options_init(&options); + options.macho_segment_name = "NODE_SEA"; + const void* data = + postject_find_resource("NODE_EMBEDDED_DATA", &size, &options); +#else + const void* data = + postject_find_resource("NODE_EMBEDDED_DATA", &size, nullptr); +#endif - std::shared_ptr backing_store = ArrayBuffer::NewBackingStore( + std::shared_ptr backing_store = ArrayBuffer::NewBackingStore( const_cast(static_cast(data)), size, [](void* /* data */, size_t /* length */, void* /* deleter_data */) {