Skip to content

Commit

Permalink
src: fix performance regression in node_file.cc
Browse files Browse the repository at this point in the history
Commits dcb6929, 4396beb and 8a96d05 turned the O(n) scan in
InternalModuleReadJSON() into an O(4n) scan. Fix the performance
regression by turning that into a linear scan again.

PR-URL: #31343
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: David Carlier <devnexen@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Jan Krems <jan.krems@gmail.com>
  • Loading branch information
bnoordhuis authored and codebytere committed Mar 14, 2020
1 parent 7b0687d commit 23a5339
Showing 1 changed file with 35 additions and 9 deletions.
44 changes: 35 additions & 9 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -829,20 +829,46 @@ static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
}

const size_t size = offset - start;
if (size == 0 || (
size == SearchString(&chars[start], size, "\"name\"") &&
size == SearchString(&chars[start], size, "\"main\"") &&
size == SearchString(&chars[start], size, "\"exports\"") &&
size == SearchString(&chars[start], size, "\"type\""))) {
args.GetReturnValue().Set(env->empty_object_string());
} else {
Local<String> chars_string =
char* p = &chars[start];
char* pe = &chars[size];
char* pos[2];
char** ppos = &pos[0];

while (p < pe) {
char c = *p++;
if (c == '"') goto quote; // Keeps code flat and inner loop small.
if (c == '\\' && p < pe && *p == '"') p++;
continue;
quote:
*ppos++ = p;
if (ppos < &pos[2]) continue;
ppos = &pos[0];

char* s = &pos[0][0];
char* se = &pos[1][-1]; // Exclude quote.
size_t n = se - s;

if (n == 4) {
if (0 == memcmp(s, "main", 4)) break;
if (0 == memcmp(s, "name", 4)) break;
if (0 == memcmp(s, "type", 4)) break;
} else if (n == 7) {
if (0 == memcmp(s, "exports", 7)) break;
}
}

Local<String> return_value;
if (p < pe) {
return_value =
String::NewFromUtf8(isolate,
&chars[start],
v8::NewStringType::kNormal,
size).ToLocalChecked();
args.GetReturnValue().Set(chars_string);
} else {
return_value = env->empty_object_string();
}

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

// Used to speed up module loading. Returns 0 if the path refers to
Expand Down

0 comments on commit 23a5339

Please sign in to comment.