diff --git a/doc/api/errors.md b/doc/api/errors.md
index 992ab1e7a21932..99af44fcb928c6 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -2414,6 +2414,13 @@ error indicates that the idle loop has failed to stop.
An attempt was made to use operations that can only be used when building
V8 startup snapshot even though Node.js isn't building one.
+
+
+### `ERR_NOT_SUPPORTED_IN_SNAPSHOT`
+
+An attempt was made to perform operations that are not supported when
+building a startup snapshot.
+
### `ERR_NO_CRYPTO`
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 18f4a2c42c39b1..2635f842666e94 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1464,6 +1464,8 @@ E('ERR_NETWORK_IMPORT_DISALLOWED',
"import of '%s' by %s is not supported: %s", Error);
E('ERR_NOT_BUILDING_SNAPSHOT',
'Operation cannot be invoked when not building startup snapshot', Error);
+E('ERR_NOT_SUPPORTED_IN_SNAPSHOT',
+ '%s is not supported in startup snapshot', Error);
E('ERR_NO_CRYPTO',
'Node.js is not compiled with OpenSSL crypto support', Error);
E('ERR_NO_ICU',
diff --git a/lib/internal/v8/startup_snapshot.js b/lib/internal/v8/startup_snapshot.js
index 49623627706bc0..5de746293d06e8 100644
--- a/lib/internal/v8/startup_snapshot.js
+++ b/lib/internal/v8/startup_snapshot.js
@@ -6,6 +6,7 @@ const {
const {
codes: {
ERR_NOT_BUILDING_SNAPSHOT,
+ ERR_NOT_SUPPORTED_IN_SNAPSHOT,
ERR_DUPLICATE_STARTUP_SNAPSHOT_MAIN_FUNCTION,
},
} = require('internal/errors');
@@ -14,11 +15,11 @@ const {
setSerializeCallback,
setDeserializeCallback,
setDeserializeMainFunction: _setDeserializeMainFunction,
+ isBuildingSnapshotBuffer,
} = internalBinding('mksnapshot');
function isBuildingSnapshot() {
- // For now this is the only way to build a snapshot.
- return require('internal/options').getOptionValue('--build-snapshot');
+ return isBuildingSnapshotBuffer[0];
}
function throwIfNotBuildingSnapshot() {
@@ -27,6 +28,12 @@ function throwIfNotBuildingSnapshot() {
}
}
+function throwIfBuildingSnapshot(reason) {
+ if (isBuildingSnapshot()) {
+ throw new ERR_NOT_SUPPORTED_IN_SNAPSHOT(reason);
+ }
+}
+
const deserializeCallbacks = [];
let deserializeCallbackIsSet = false;
function runDeserializeCallbacks() {
@@ -102,6 +109,7 @@ function setDeserializeMainFunction(callback, data) {
module.exports = {
initializeCallbacks,
runDeserializeCallbacks,
+ throwIfBuildingSnapshot,
// Exposed to require('v8').startupSnapshot
namespace: {
addDeserializeCallback,
diff --git a/lib/internal/worker.js b/lib/internal/worker.js
index eda9dbcdeb5c04..401bc43550ea7f 100644
--- a/lib/internal/worker.js
+++ b/lib/internal/worker.js
@@ -60,7 +60,9 @@ const { deserializeError } = require('internal/error_serdes');
const { fileURLToPath, isURL, pathToFileURL } = require('internal/url');
const { kEmptyObject } = require('internal/util');
const { validateArray, validateString } = require('internal/validators');
-
+const {
+ throwIfBuildingSnapshot,
+} = require('internal/v8/startup_snapshot');
const {
ownsProcessState,
isMainThread,
@@ -129,6 +131,7 @@ function assignEnvironmentData(data) {
class Worker extends EventEmitter {
constructor(filename, options = kEmptyObject) {
+ throwIfBuildingSnapshot('Creating workers');
super();
const isInternal = arguments[2] === kIsInternal;
debug(
diff --git a/src/api/embed_helpers.cc b/src/api/embed_helpers.cc
index 5c8b733737a2e6..341d131f24f753 100644
--- a/src/api/embed_helpers.cc
+++ b/src/api/embed_helpers.cc
@@ -142,8 +142,8 @@ CommonEnvironmentSetup::CommonEnvironmentSetup(
impl_->isolate_data.reset(CreateIsolateData(
isolate, loop, platform, impl_->allocator.get(), snapshot_data));
- impl_->isolate_data->options()->build_snapshot =
- impl_->snapshot_creator.has_value();
+ impl_->isolate_data->set_is_building_snapshot(
+ impl_->snapshot_creator.has_value());
if (snapshot_data) {
impl_->env.reset(make_env(this));
diff --git a/src/base_object_types.h b/src/base_object_types.h
index 4916a20bbc6421..bb7a0e064b0b72 100644
--- a/src/base_object_types.h
+++ b/src/base_object_types.h
@@ -12,6 +12,7 @@ namespace node {
#define SERIALIZABLE_BINDING_TYPES(V) \
V(encoding_binding_data, encoding_binding::BindingData) \
V(fs_binding_data, fs::BindingData) \
+ V(mksnapshot_binding_data, mksnapshot::BindingData) \
V(v8_binding_data, v8_utils::BindingData) \
V(blob_binding_data, BlobBindingData) \
V(process_binding_data, process::BindingData) \
diff --git a/src/env.h b/src/env.h
index 5359436be31e76..354d0bf414c55a 100644
--- a/src/env.h
+++ b/src/env.h
@@ -136,6 +136,9 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
void MemoryInfo(MemoryTracker* tracker) const override;
IsolateDataSerializeInfo Serialize(v8::SnapshotCreator* creator);
+ bool is_building_snapshot() const { return is_building_snapshot_; }
+ void set_is_building_snapshot(bool value) { is_building_snapshot_ = value; }
+
inline uv_loop_t* event_loop() const;
inline MultiIsolatePlatform* platform() const;
inline const SnapshotData* snapshot_data() const;
@@ -219,6 +222,7 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
const SnapshotData* snapshot_data_;
std::shared_ptr options_;
worker::Worker* worker_context_ = nullptr;
+ bool is_building_snapshot_ = false;
};
struct ContextInfo {
diff --git a/src/node.cc b/src/node.cc
index 1806693d4bd204..acab0cb3d960b6 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -283,7 +283,7 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) {
auto reset_entry_point =
OnScopeLeave([&]() { env->set_embedder_entry_point({}); });
- const char* entry = env->isolate_data()->options()->build_snapshot
+ const char* entry = env->isolate_data()->is_building_snapshot()
? "internal/main/mksnapshot"
: "internal/main/embedding";
@@ -311,7 +311,7 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) {
return StartExecution(env, "internal/main/inspect");
}
- if (env->isolate_data()->options()->build_snapshot) {
+ if (env->isolate_data()->is_building_snapshot()) {
return StartExecution(env, "internal/main/mksnapshot");
}
diff --git a/src/node_binding.h b/src/node_binding.h
index f04be60c3890f0..dd7667899e5a7f 100644
--- a/src/node_binding.h
+++ b/src/node_binding.h
@@ -37,6 +37,7 @@ static_assert(static_cast(NM_F_LINKED) ==
V(contextify) \
V(encoding_binding) \
V(fs) \
+ V(mksnapshot) \
V(timers) \
V(process_methods) \
V(performance) \
diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc
index f0dc6ca275b007..7488ec663bf1a8 100644
--- a/src/node_main_instance.cc
+++ b/src/node_main_instance.cc
@@ -56,6 +56,8 @@ NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
platform,
array_buffer_allocator_.get(),
snapshot_data->AsEmbedderWrapper().get()));
+ isolate_data_->set_is_building_snapshot(
+ per_process::cli_options->per_isolate->build_snapshot);
isolate_data_->max_young_gen_size =
isolate_params_->constraints.max_young_generation_size_in_bytes();
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
index 5c283bcdbeb22e..cc51294ada755b 100644
--- a/src/node_snapshotable.cc
+++ b/src/node_snapshotable.cc
@@ -3,6 +3,7 @@
#include
#include
#include
+#include "aliased_buffer-inl.h"
#include "base_object-inl.h"
#include "debug_utils-inl.h"
#include "encoding_binding.h"
@@ -33,6 +34,7 @@ namespace node {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
@@ -1498,8 +1500,6 @@ void SerializeSnapshotableObjects(Realm* realm,
});
}
-namespace mksnapshot {
-
// NB: This is also used by the regular embedding codepath.
void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
@@ -1572,16 +1572,89 @@ void SetDeserializeMainFunction(const FunctionCallbackInfo& args) {
env->set_snapshot_deserialize_main(args[0].As());
}
-void Initialize(Local