Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,12 +641,14 @@ enum Flags : uint64_t {
};
} // namespace EnvironmentFlags

// Bit 0 is a config-level flag (kWithoutCodeCache).
// Bits 1..31 are dynamically assigned at runtime to env-affecting boolean
// options that carry affects_snapshot=true, in alphabetical order by flag
// name. The mapping is computed by GetSnapshotAffectingOptions() so there are
// no named constants for those bits here.
enum class SnapshotFlags : uint32_t {
kDefault = 0,
// Whether code cache should be generated as part of the snapshot.
// Code cache reduces the time spent on compiling functions included
// in the snapshot at the expense of a bigger snapshot size and
// potentially breaking portability of the snapshot.
kWithoutCodeCache = 1 << 0,
};

Expand Down
9 changes: 6 additions & 3 deletions src/node_options-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ void OptionsParser<Options>::AddOption(const char* name,
bool Options::*field,
OptionEnvvarSettings env_setting,
bool default_is_true,
OptionNamespaces namespace_id) {
OptionNamespaces namespace_id,
bool affects_snapshot) {
options_.emplace(name,
OptionInfo{kBoolean,
std::make_shared<SimpleOptionField<bool>>(field),
env_setting,
help_text,
default_is_true,
NamespaceEnumToString(namespace_id)});
NamespaceEnumToString(namespace_id),
affects_snapshot});
}

template <typename Options>
Expand Down Expand Up @@ -229,7 +231,8 @@ auto OptionsParser<Options>::Convert(
original.env_setting,
original.help_text,
original.default_is_true,
original.namespace_id};
original.namespace_id,
original.affects_snapshot};
}

template <typename Options>
Expand Down
116 changes: 103 additions & 13 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <string_view>
#include <vector>

using v8::Array;
using v8::Boolean;
using v8::Context;
using v8::FunctionCallbackInfo;
Expand Down Expand Up @@ -586,39 +587,55 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"experimental EventSource API",
&EnvironmentOptions::experimental_eventsource,
kAllowedInEnvvar,
false);
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--experimental-fetch", "", NoOp{}, kAllowedInEnvvar);
#if HAVE_FFI
AddOption("--experimental-ffi",
"experimental node:ffi module",
&EnvironmentOptions::experimental_ffi,
kAllowedInEnvvar,
false);
false,
OptionNamespaces::kNoNamespace,
true);
#endif // HAVE_FFI
AddOption("--experimental-websocket",
"experimental WebSocket API",
&EnvironmentOptions::experimental_websocket,
kAllowedInEnvvar,
true,
OptionNamespaces::kNoNamespace,
true);
AddOption("--experimental-global-customevent", "", NoOp{}, kAllowedInEnvvar);
AddOption("--experimental-sqlite",
"experimental node:sqlite module",
&EnvironmentOptions::experimental_sqlite,
kAllowedInEnvvar,
HAVE_SQLITE);
HAVE_SQLITE,
OptionNamespaces::kNoNamespace,
true);
AddOption("--experimental-stream-iter",
"experimental iterable streams API (node:stream/iter)",
&EnvironmentOptions::experimental_stream_iter,
kAllowedInEnvvar);
AddOption("--experimental-quic",
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
#ifndef OPENSSL_NO_QUIC
AddOption("--experimental-quic",
"experimental QUIC support",
&EnvironmentOptions::experimental_quic,
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
#else
AddOption("--experimental-quic",
"" /* undocumented when no-op */,
NoOp{},
#endif
kAllowedInEnvvar);
#endif
AddOption("--experimental-webstorage",
"experimental Web Storage API",
&EnvironmentOptions::webstorage,
Expand Down Expand Up @@ -720,7 +737,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--experimental-vm-modules",
"experimental ES Module support in vm module",
&EnvironmentOptions::experimental_vm_modules,
kAllowedInEnvvar);
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--experimental-worker", "", NoOp{}, kAllowedInEnvvar);
AddOption("--experimental-report", "", NoOp{}, kAllowedInEnvvar);
AddOption(
Expand All @@ -731,11 +751,20 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::async_context_frame,
kAllowedInEnvvar,
true);
AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals);
AddOption("--expose-internals",
"",
&EnvironmentOptions::expose_internals,
kDisallowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--frozen-intrinsics",
"experimental frozen intrinsics support",
&EnvironmentOptions::frozen_intrinsics,
kAllowedInEnvvar);
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--heapsnapshot-signal",
"Generate heap snapshot on specified signal",
&EnvironmentOptions::heap_snapshot_signal,
Expand Down Expand Up @@ -763,6 +792,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"silence deprecation warnings",
&EnvironmentOptions::deprecation,
kAllowedInEnvvar,
true,
OptionNamespaces::kNoNamespace,
true);
AddOption("--force-async-hooks-checks",
"disable checks for async_hooks",
Expand All @@ -789,6 +820,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"silence all process warnings",
&EnvironmentOptions::warnings,
kAllowedInEnvvar,
true,
OptionNamespaces::kNoNamespace,
true);
AddOption("--disable-warning",
"silence specific process warnings",
Expand All @@ -801,7 +834,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--pending-deprecation",
"emit pending deprecation warnings",
&EnvironmentOptions::pending_deprecation,
kAllowedInEnvvar);
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--use-env-proxy",
"parse proxy settings from HTTP_PROXY/HTTPS_PROXY/NO_PROXY"
"environment variables and apply the setting in global HTTP/HTTPS "
Expand Down Expand Up @@ -1043,11 +1079,17 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--throw-deprecation",
"throw an exception on deprecations",
&EnvironmentOptions::throw_deprecation,
kAllowedInEnvvar);
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--trace-deprecation",
"show stack traces on deprecations",
&EnvironmentOptions::trace_deprecation,
kAllowedInEnvvar);
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--trace-exit",
"show stack trace when an environment exits",
&EnvironmentOptions::trace_exit,
Expand All @@ -1068,7 +1110,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--trace-warnings",
"show stack traces on process warnings",
&EnvironmentOptions::trace_warnings,
kAllowedInEnvvar);
kAllowedInEnvvar,
false,
OptionNamespaces::kNoNamespace,
true);
AddOption("--trace-promises",
"show stack traces on promise initialization and resolution",
&EnvironmentOptions::trace_promises,
Expand Down Expand Up @@ -2017,6 +2062,34 @@ void GetNamespaceOptionsInputType(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(namespaces_metadata);
}

// Return an array of {name, defaultIsTrue} for every boolean option marked
// affects_snapshot=true, sorted alphabetically.
void GetSnapshotAffectingFlags(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Environment* env = Environment::GetCurrent(context);

Mutex::ScopedLock lock(per_process::cli_options_mutex);

auto options = node::GetSnapshotAffectingOptions(*env->options());

Local<Array> result = Array::New(isolate, options.size());
for (size_t i = 0; i < options.size(); i++) {
Local<Object> obj = Object::New(isolate);
obj->Set(context,
FIXED_ONE_BYTE_STRING(isolate, "name"),
ToV8Value(context, options[i].name).ToLocalChecked())
.Check();
obj->Set(context,
FIXED_ONE_BYTE_STRING(isolate, "defaultIsTrue"),
Boolean::New(isolate, options[i].default_is_true))
.Check();
result->Set(context, i, obj).Check();
}

args.GetReturnValue().Set(result);
}

// Return an array containing all currently active options as flag
// strings from all sources (command line, NODE_OPTIONS, config file)
void GetOptionsAsFlags(const FunctionCallbackInfo<Value>& args) {
Expand Down Expand Up @@ -2138,6 +2211,8 @@ void Initialize(Local<Object> target,
context, target, "getCLIOptionsValues", GetCLIOptionsValues);
SetMethodNoSideEffect(
context, target, "getCLIOptionsInfo", GetCLIOptionsInfo);
SetMethodNoSideEffect(
context, target, "getSnapshotAffectingFlags", GetSnapshotAffectingFlags);
SetMethodNoSideEffect(
context, target, "getOptionsAsFlags", GetOptionsAsFlags);
SetMethodNoSideEffect(
Expand Down Expand Up @@ -2172,6 +2247,7 @@ void Initialize(Local<Object> target,
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(GetCLIOptionsValues);
registry->Register(GetCLIOptionsInfo);
registry->Register(GetSnapshotAffectingFlags);
registry->Register(GetOptionsAsFlags);
registry->Register(GetEmbedderOptions);
registry->Register(GetEnvOptionsInputType);
Expand Down Expand Up @@ -2246,6 +2322,20 @@ std::vector<std::string> ParseNodeOptionsEnvVar(
}
return env_argv;
}
std::vector<SnapshotFlagInfo> GetSnapshotAffectingOptions(
const EnvironmentOptions& opts) {
std::vector<SnapshotFlagInfo> result;
options_parser::_eop_instance.ForEachSnapshotAffecting(
const_cast<EnvironmentOptions*>(&opts),
[&](const std::string& name, bool val, bool default_is_true) {
result.push_back({name, val, default_is_true});
});
std::sort(result.begin(), result.end(), [](const auto& a, const auto& b) {
return a.name < b.name;
});
return result;
}

} // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(options, node::options_parser::Initialize)
Expand Down
43 changes: 36 additions & 7 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,13 +476,15 @@ class OptionsParser {
// default_is_true is only a hint in printing help text, it does not
// affect the default value of the option. Set the default value in the
// Options struct instead.
void AddOption(
const char* name,
const char* help_text,
bool Options::*field,
OptionEnvvarSettings env_setting = kDisallowedInEnvvar,
bool default_is_true = false,
OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace);
// affects_snapshot marks that the flag's effective value must match between
// snapshot build and load time.
void AddOption(const char* name,
const char* help_text,
bool Options::*field,
OptionEnvvarSettings env_setting = kDisallowedInEnvvar,
bool default_is_true = false,
OptionNamespaces namespace_id = OptionNamespaces::kNoNamespace,
bool affects_snapshot = false);
void AddOption(
const char* name,
const char* help_text,
Expand Down Expand Up @@ -573,6 +575,18 @@ class OptionsParser {
OptionEnvvarSettings required_env_settings,
std::vector<std::string>* const errors) const;

// Calls fn(name, value, default_is_true) for every boolean option that has
// affects_snapshot=true, in unspecified order.
template <typename Fn>
void ForEachSnapshotAffecting(Options* options, Fn&& fn) const {
for (const auto& [name, info] : options_) {
if (info.affects_snapshot && info.type == kBoolean && info.field) {
bool val = *Lookup<bool>(info.field, options);
fn(name, val, info.default_is_true);
}
}
}

private:
// We support the wide variety of different option types by remembering
// how to access them, given a certain `Options` struct.
Expand Down Expand Up @@ -622,6 +636,7 @@ class OptionsParser {
std::string help_text;
bool default_is_true = false;
std::string namespace_id;
bool affects_snapshot = false;
};

// An implied option is composed of the information on where to store a
Expand Down Expand Up @@ -693,6 +708,20 @@ void HandleEnvOptions(std::shared_ptr<EnvironmentOptions> env_options,

std::vector<std::string> ParseNodeOptionsEnvVar(
const std::string& node_options, std::vector<std::string>* errors);

// Describes one snapshot-affecting boolean option.
struct SnapshotFlagInfo {
std::string name; // canonical CLI flag name
bool value; // current effective value
bool default_is_true; // true if the flag defaults to on (--no-* form)
};

// Returns every boolean EnvironmentOption marked affects_snapshot=true,
// sorted alphabetically by name. The sort order determines bit positions
// in SnapshotFlags (bit 1 = index 0, bit 2 = index 1, ...).
std::vector<SnapshotFlagInfo> GetSnapshotAffectingOptions(
const EnvironmentOptions& opts);

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
Loading
Loading