From ecef817a287d3adf9246bcf15c5d86f351595146 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 11 Nov 2015 12:28:41 -0700 Subject: [PATCH] node: improve accessor perf of process.env Set process.env array entries in JS. PR-URL: https://github.com/nodejs/node/pull/3780 Reviewed-By: Fedor Indutny --- benchmark/misc/bench-env.js | 18 ++++++++++++++++ src/node.cc | 43 ++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 benchmark/misc/bench-env.js diff --git a/benchmark/misc/bench-env.js b/benchmark/misc/bench-env.js new file mode 100644 index 0000000000..66f966f587 --- /dev/null +++ b/benchmark/misc/bench-env.js @@ -0,0 +1,18 @@ +'use strict'; + +const common = require('../common'); + +const bench = common.createBenchmark(main, { + n: [1e5], +}); + + +function main(conf) { + const n = conf.n >>> 0; + bench.start(); + for (var i = 0; i < n; i++) { + // Access every item in object to process values. + Object.keys(process.env); + } + bench.end(n); +} diff --git a/src/node.cc b/src/node.cc index e03d541f3c..f9797e664e 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2560,23 +2560,35 @@ static void EnvDeleter(Local property, static void EnvEnumerator(const PropertyCallbackInfo& info) { - Isolate* isolate = info.GetIsolate(); + Environment* env = Environment::GetCurrent(info); + Isolate* isolate = env->isolate(); + Local ctx = env->context(); + Local fn = env->push_values_to_array_function(); + Local argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t idx = 0; + #ifdef __POSIX__ int size = 0; while (environ[size]) size++; - Local envarr = Array::New(isolate, size); + Local envarr = Array::New(isolate); for (int i = 0; i < size; ++i) { const char* var = environ[i]; const char* s = strchr(var, '='); const int length = s ? s - var : strlen(var); - Local name = String::NewFromUtf8(isolate, - var, - String::kNormalString, - length); - envarr->Set(i, name); + argv[idx] = String::NewFromUtf8(isolate, + var, + String::kNormalString, + length); + if (++idx >= ARRAY_SIZE(argv)) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + idx = 0; + } + } + if (idx > 0) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); } #else // _WIN32 WCHAR* environment = GetEnvironmentStringsW(); @@ -2584,7 +2596,6 @@ static void EnvEnumerator(const PropertyCallbackInfo& info) { return; // This should not happen. Local envarr = Array::New(isolate); WCHAR* p = environment; - int i = 0; while (*p) { WCHAR *s; if (*p == L'=') { @@ -2599,13 +2610,19 @@ static void EnvEnumerator(const PropertyCallbackInfo& info) { } const uint16_t* two_byte_buffer = reinterpret_cast(p); const size_t two_byte_buffer_len = s - p; - Local value = String::NewFromTwoByte(isolate, - two_byte_buffer, - String::kNormalString, - two_byte_buffer_len); - envarr->Set(i++, value); + argv[idx] = String::NewFromTwoByte(isolate, + two_byte_buffer, + String::kNormalString, + two_byte_buffer_len); + if (++idx >= ARRAY_SIZE(argv)) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + idx = 0; + } p = s + wcslen(s) + 1; } + if (idx > 0) { + fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); + } FreeEnvironmentStringsW(environment); #endif