src: use simdjson to parse SEA configuration · nodejs/node@64add63
@@ -3,14 +3,14 @@
33#include "blob_serializer_deserializer-inl.h"
44#include "debug_utils-inl.h"
55#include "env-inl.h"
6-#include "json_parser.h"
76#include "node_contextify.h"
87#include "node_errors.h"
98#include "node_external_reference.h"
109#include "node_internals.h"
1110#include "node_snapshot_builder.h"
1211#include "node_union_bytes.h"
1312#include "node_v8_platform-inl.h"
13+#include "simdjson.h"
1414#include "util-inl.h"
15151616// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
@@ -303,79 +303,131 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
303303 }
304304305305 SeaConfig result;
306- JSONParser parser;
307-if (!parser.Parse(config)) {
308-FPrintF(stderr, "Cannot parse JSON from %s\n", config_path);
309-return std::nullopt;
310- }
311306312- result.main_path =
313- parser.GetTopLevelStringField("main").value_or(std::string());
314-if (result.main_path.empty()) {
315-FPrintF(stderr,
316-"\"main\" field of %s is not a non-empty string\n",
317- config_path);
318-return std::nullopt;
319- }
307+ simdjson::ondemand::parser parser;
308+ simdjson::ondemand::document document;
309+ simdjson::ondemand::object main_object;
310+ simdjson::error_code error =
311+ parser.iterate(simdjson::pad(config)).get(document);
320312321- result.output_path =
322- parser.GetTopLevelStringField("output").value_or(std::string());
323-if (result.output_path.empty()) {
313+if (!error) {
314+ error = document.get_object().get(main_object);
315+ }
316+if (error) {
324317FPrintF(stderr,
325-"\"output\" field of %s is not a non-empty string\n",
326- config_path);
318+"Cannot parse JSON from %s: %s\n",
319+ config_path,
320+simdjson::error_message(error));
327321return std::nullopt;
328322 }
329323330- std::optional<bool> disable_experimental_sea_warning =
331- parser.GetTopLevelBoolField("disableExperimentalSEAWarning");
332-if (!disable_experimental_sea_warning.has_value()) {
333-FPrintF(stderr,
324+bool use_snapshot_value = false;
325+bool use_code_cache_value = false;
326+327+for (auto field : main_object) {
328+ std::string_view key;
329+if (field.unescaped_key().get(key)) {
330+FPrintF(stderr, "Cannot read key from %s\n", config_path);
331+return std::nullopt;
332+ }
333+if (key == "main") {
334+if (field.value().get_string().get(result.main_path) ||
335+ result.main_path.empty()) {
336+FPrintF(stderr,
337+"\"main\" field of %s is not a non-empty string\n",
338+ config_path);
339+return std::nullopt;
340+ }
341+ } else if (key == "output") {
342+if (field.value().get_string().get(result.output_path) ||
343+ result.output_path.empty()) {
344+FPrintF(stderr,
345+"\"output\" field of %s is not a non-empty string\n",
346+ config_path);
347+return std::nullopt;
348+ }
349+ } else if (key == "disableExperimentalSEAWarning") {
350+bool disable_experimental_sea_warning;
351+if (field.value().get_bool().get(disable_experimental_sea_warning)) {
352+FPrintF(
353+ stderr,
334354"\"disableExperimentalSEAWarning\" field of %s is not a Boolean\n",
335355 config_path);
336-return std::nullopt;
337- }
338-if (disable_experimental_sea_warning.value()) {
339- result.flags |= SeaFlags::kDisableExperimentalSeaWarning;
356+return std::nullopt;
357+ }
358+if (disable_experimental_sea_warning) {
359+ result.flags |= SeaFlags::kDisableExperimentalSeaWarning;
360+ }
361+ } else if (key == "useSnapshot") {
362+if (field.value().get_bool().get(use_snapshot_value)) {
363+FPrintF(stderr,
364+"\"useSnapshot\" field of %s is not a Boolean\n",
365+ config_path);
366+return std::nullopt;
367+ }
368+if (use_snapshot_value) {
369+ result.flags |= SeaFlags::kUseSnapshot;
370+ }
371+ } else if (key == "useCodeCache") {
372+if (field.value().get_bool().get(use_code_cache_value)) {
373+FPrintF(stderr,
374+"\"useCodeCache\" field of %s is not a Boolean\n",
375+ config_path);
376+return std::nullopt;
377+ }
378+if (use_code_cache_value) {
379+ result.flags |= SeaFlags::kUseCodeCache;
380+ }
381+ } else if (key == "assets") {
382+ simdjson::ondemand::object assets_object;
383+if (field.value().get_object().get(assets_object)) {
384+FPrintF(stderr,
385+"\"assets\" field of %s is not a map of strings\n",
386+ config_path);
387+return std::nullopt;
388+ }
389+ simdjson::ondemand::value asset_value;
390+for (auto asset_field : assets_object) {
391+ std::string_view key_str;
392+ std::string_view value_str;
393+if (asset_field.unescaped_key().get(key_str) ||
394+ asset_field.value().get(asset_value) ||
395+ asset_value.get_string().get(value_str)) {
396+FPrintF(stderr,
397+"\"assets\" field of %s is not a map of strings\n",
398+ config_path);
399+return std::nullopt;
400+ }
401+402+ result.assets.emplace(key_str, value_str);
403+ }
404+405+if (!result.assets.empty()) {
406+ result.flags |= SeaFlags::kIncludeAssets;
407+ }
408+ }
340409 }
341410342- std::optional<bool> use_snapshot = parser.GetTopLevelBoolField("useSnapshot");
343-if (!use_snapshot.has_value()) {
344-FPrintF(
345- stderr, "\"useSnapshot\" field of %s is not a Boolean\n", config_path);
346-return std::nullopt;
347- }
348-if (use_snapshot.value()) {
349- result.flags |= SeaFlags::kUseSnapshot;
411+if (static_cast<bool>(result.flags & SeaFlags::kUseSnapshot) &&
412+static_cast<bool>(result.flags & SeaFlags::kUseCodeCache)) {
413+// TODO(joyeecheung): code cache in snapshot should be configured by
414+// separate snapshot configurations.
415+FPrintF(stderr,
416+"\"useCodeCache\" is redundant when \"useSnapshot\" is true\n");
350417 }
351418352- std::optional<bool> use_code_cache =
353- parser.GetTopLevelBoolField("useCodeCache");
354-if (!use_code_cache.has_value()) {
355-FPrintF(
356- stderr, "\"useCodeCache\" field of %s is not a Boolean\n", config_path);
419+if (result.main_path.empty()) {
420+FPrintF(stderr,
421+"\"main\" field of %s is not a non-empty string\n",
422+ config_path);
357423return std::nullopt;
358424 }
359-if (use_code_cache.value()) {
360-if (use_snapshot.value()) {
361-// TODO(joyeecheung): code cache in snapshot should be configured by
362-// separate snapshot configurations.
363-FPrintF(stderr,
364-"\"useCodeCache\" is redundant when \"useSnapshot\" is true\n");
365- } else {
366- result.flags |= SeaFlags::kUseCodeCache;
367- }
368- }
369425370-auto assets_opt = parser.GetTopLevelStringDict("assets");
371-if (!assets_opt.has_value()) {
426+if (result.output_path.empty()) {
372427FPrintF(stderr,
373-"\"assets\" field of %s is not a map of strings\n",
428+"\"output\" field of %s is not a non-empty string\n",
374429 config_path);
375430return std::nullopt;
376- } else if (!assets_opt.value().empty()) {
377- result.flags |= SeaFlags::kIncludeAssets;
378- result.assets = std::move(assets_opt.value());
379431 }
380432381433return result;