Skip to content
Closed
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
164 changes: 108 additions & 56 deletions src/node_sea.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
#include "blob_serializer_deserializer-inl.h"
#include "debug_utils-inl.h"
#include "env-inl.h"
#include "json_parser.h"
#include "node_contextify.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_internals.h"
#include "node_snapshot_builder.h"
#include "node_union_bytes.h"
#include "node_v8_platform-inl.h"
#include "simdjson.h"
#include "util-inl.h"

// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
Expand Down Expand Up @@ -303,79 +303,131 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
}

SeaConfig result;
JSONParser parser;
if (!parser.Parse(config)) {
FPrintF(stderr, "Cannot parse JSON from %s\n", config_path);
return std::nullopt;
}

result.main_path =
parser.GetTopLevelStringField("main").value_or(std::string());
if (result.main_path.empty()) {
FPrintF(stderr,
"\"main\" field of %s is not a non-empty string\n",
config_path);
return std::nullopt;
}
simdjson::ondemand::parser parser;
simdjson::ondemand::document document;
simdjson::ondemand::object main_object;
simdjson::error_code error =
parser.iterate(simdjson::pad(config)).get(document);

result.output_path =
parser.GetTopLevelStringField("output").value_or(std::string());
if (result.output_path.empty()) {
if (!error) {
error = document.get_object().get(main_object);
}
if (error) {
FPrintF(stderr,
"\"output\" field of %s is not a non-empty string\n",
config_path);
"Cannot parse JSON from %s: %s\n",
config_path,
simdjson::error_message(error));
return std::nullopt;
}

std::optional<bool> disable_experimental_sea_warning =
parser.GetTopLevelBoolField("disableExperimentalSEAWarning");
if (!disable_experimental_sea_warning.has_value()) {
FPrintF(stderr,
bool use_snapshot_value = false;
bool use_code_cache_value = false;

for (auto field : main_object) {
std::string_view key;
if (field.unescaped_key().get(key)) {
FPrintF(stderr, "Cannot read key from %s\n", config_path);
return std::nullopt;
}
if (key == "main") {
if (field.value().get_string().get(result.main_path) ||
result.main_path.empty()) {
FPrintF(stderr,
"\"main\" field of %s is not a non-empty string\n",
config_path);
return std::nullopt;
}
} else if (key == "output") {
if (field.value().get_string().get(result.output_path) ||
result.output_path.empty()) {
FPrintF(stderr,
"\"output\" field of %s is not a non-empty string\n",
config_path);
return std::nullopt;
}
} else if (key == "disableExperimentalSEAWarning") {
bool disable_experimental_sea_warning;
if (field.value().get_bool().get(disable_experimental_sea_warning)) {
FPrintF(
stderr,
"\"disableExperimentalSEAWarning\" field of %s is not a Boolean\n",
config_path);
return std::nullopt;
}
if (disable_experimental_sea_warning.value()) {
result.flags |= SeaFlags::kDisableExperimentalSeaWarning;
return std::nullopt;
}
if (disable_experimental_sea_warning) {
result.flags |= SeaFlags::kDisableExperimentalSeaWarning;
}
} else if (key == "useSnapshot") {
if (field.value().get_bool().get(use_snapshot_value)) {
FPrintF(stderr,
"\"useSnapshot\" field of %s is not a Boolean\n",
config_path);
return std::nullopt;
}
if (use_snapshot_value) {
result.flags |= SeaFlags::kUseSnapshot;
}
} else if (key == "useCodeCache") {
if (field.value().get_bool().get(use_code_cache_value)) {
FPrintF(stderr,
"\"useCodeCache\" field of %s is not a Boolean\n",
config_path);
return std::nullopt;
}
if (use_code_cache_value) {
result.flags |= SeaFlags::kUseCodeCache;
}
} else if (key == "assets") {
simdjson::ondemand::object assets_object;
if (field.value().get_object().get(assets_object)) {
FPrintF(stderr,
"\"assets\" field of %s is not a map of strings\n",
config_path);
return std::nullopt;
}
simdjson::ondemand::value asset_value;
for (auto asset_field : assets_object) {
std::string_view key_str;
std::string_view value_str;
if (asset_field.unescaped_key().get(key_str) ||
asset_field.value().get(asset_value) ||
asset_value.get_string().get(value_str)) {
FPrintF(stderr,
"\"assets\" field of %s is not a map of strings\n",
config_path);
return std::nullopt;
}

result.assets.emplace(key_str, value_str);
}

if (!result.assets.empty()) {
result.flags |= SeaFlags::kIncludeAssets;
}
}
}

std::optional<bool> use_snapshot = parser.GetTopLevelBoolField("useSnapshot");
if (!use_snapshot.has_value()) {
FPrintF(
stderr, "\"useSnapshot\" field of %s is not a Boolean\n", config_path);
return std::nullopt;
}
if (use_snapshot.value()) {
result.flags |= SeaFlags::kUseSnapshot;
if (static_cast<bool>(result.flags & SeaFlags::kUseSnapshot) &&
static_cast<bool>(result.flags & SeaFlags::kUseCodeCache)) {
// TODO(joyeecheung): code cache in snapshot should be configured by
// separate snapshot configurations.
FPrintF(stderr,
"\"useCodeCache\" is redundant when \"useSnapshot\" is true\n");
}

std::optional<bool> use_code_cache =
parser.GetTopLevelBoolField("useCodeCache");
if (!use_code_cache.has_value()) {
FPrintF(
stderr, "\"useCodeCache\" field of %s is not a Boolean\n", config_path);
if (result.main_path.empty()) {
FPrintF(stderr,
"\"main\" field of %s is not a non-empty string\n",
config_path);
return std::nullopt;
}
if (use_code_cache.value()) {
if (use_snapshot.value()) {
// TODO(joyeecheung): code cache in snapshot should be configured by
// separate snapshot configurations.
FPrintF(stderr,
"\"useCodeCache\" is redundant when \"useSnapshot\" is true\n");
} else {
result.flags |= SeaFlags::kUseCodeCache;
}
}

auto assets_opt = parser.GetTopLevelStringDict("assets");
if (!assets_opt.has_value()) {
if (result.output_path.empty()) {
FPrintF(stderr,
"\"assets\" field of %s is not a map of strings\n",
"\"output\" field of %s is not a non-empty string\n",
config_path);
return std::nullopt;
} else if (!assets_opt.value().empty()) {
result.flags |= SeaFlags::kIncludeAssets;
result.assets = std::move(assets_opt.value());
}

return result;
Expand Down
Loading
Loading