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) {

324317

FPrintF(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));

327321

return 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);

357423

return 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()) {

372427

FPrintF(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);

375430

return std::nullopt;

376-

} else if (!assets_opt.value().empty()) {

377-

result.flags |= SeaFlags::kIncludeAssets;

378-

result.assets = std::move(assets_opt.value());

379431

}

380432381433

return result;