From a2f1825cb56e9414addfaf346a8fee541292a709 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 13 Jan 2020 14:23:20 +0100 Subject: [PATCH] src: fix performance regression in node_file.cc 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: https://github.com/nodejs/node/pull/31343 Reviewed-By: Colin Ihrig Reviewed-By: Guy Bedford Reviewed-By: David Carlier Reviewed-By: Anna Henningsen Reviewed-By: Rich Trott Reviewed-By: Jan Krems --- src/node_file.cc | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/node_file.cc b/src/node_file.cc index a87126887a1d86..23af6abd1e510b 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -829,20 +829,46 @@ static void InternalModuleReadJSON(const FunctionCallbackInfo& 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 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 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