Repository: nodejs/node
Pull request: src: use simdjson to parse --snapshot-config

Refs: https://github.com/nodejs/node/issues/59288

<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


Changed files:
filename: src/node_snapshotable.cc
patch: @@ -11,7 +11,6 @@
 #include "embedded_data.h"
 #include "encoding_binding.h"
 #include "env-inl.h"
-#include "json_parser.h"
 #include "node_blob.h"
 #include "node_builtins.h"
 #include "node_contextify.h"
@@ -27,6 +26,7 @@
 #include "node_url.h"
 #include "node_v8.h"
 #include "node_v8_platform-inl.h"
+#include "simdjson.h"
 #include "timers.h"
 
 #if HAVE_INSPECTOR
@@ -909,32 +909,61 @@ std::optional<SnapshotConfig> ReadSnapshotConfig(const char* config_path) {
     return std::nullopt;
   }
 
-  JSONParser parser;
-  if (!parser.Parse(config_content)) {
-    FPrintF(stderr, "Cannot parse JSON from %s\n", config_path);
-    return std::nullopt;
-  }
-
   SnapshotConfig result;
-  result.builder_script_path = parser.GetTopLevelStringField("builder");
-  if (!result.builder_script_path.has_value()) {
+
+  simdjson::ondemand::parser parser;
+  simdjson::ondemand::document document;
+  simdjson::ondemand::object main_object;
+  simdjson::error_code error =
+      parser.iterate(simdjson::pad(config_content)).get(document);
+
+  if (!error) {
+    error = document.get_object().get(main_object);
+  }
+  if (error) {
     FPrintF(stderr,
-            "\"builder\" 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> WithoutCodeCache =
-      parser.GetTopLevelBoolField("withoutCodeCache");
-  if (!WithoutCodeCache.has_value()) {
+  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 == "builder") {
+      std::string builder_path;
+      if (field.value().get_string().get(builder_path) ||
+          builder_path.empty()) {
+        FPrintF(stderr,
+                "\"builder\" field of %s is not a non-empty string\n",
+                config_path);
+        return std::nullopt;
+      }
+      result.builder_script_path = builder_path;
+    } else if (key == "withoutCodeCache") {
+      bool without_code_cache_value = false;
+      if (field.value().get_bool().get(without_code_cache_value)) {
+        FPrintF(stderr,
+                "\"withoutCodeCache\" field of %s is not a boolean\n",
+                config_path);
+        return std::nullopt;
+      }
+      if (without_code_cache_value) {
+        result.flags |= SnapshotFlags::kWithoutCodeCache;
+      }
+    }
+  }
+
+  if (!result.builder_script_path.has_value()) {
     FPrintF(stderr,
-            "\"withoutCodeCache\" field of %s is not a boolean\n",
+            "\"builder\" field of %s is not a non-empty string\n",
             config_path);
     return std::nullopt;
   }
-  if (WithoutCodeCache.value()) {
-    result.flags |= SnapshotFlags::kWithoutCodeCache;
-  }
 
   return result;
 }