Skip to content

Commit

Permalink
querystring: improve escape() performance
Browse files Browse the repository at this point in the history
This commit improves escape() performance by up to 15% with the
existing querystring-stringify benchmarks by reducing the number
of string concatentations. A potential deopt is also avoided by
making sure the index passed to charCodeAt() is within bounds.

PR-URL: #5012
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Roman Reiss <me@silverwind.io>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
mscdex committed Feb 13, 2016
1 parent c8e650d commit 00638ac
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 11 deletions.
3 changes: 2 additions & 1 deletion benchmark/querystring/querystring-stringify.js
Expand Up @@ -4,7 +4,7 @@ var v8 = require('v8');

var bench = common.createBenchmark(main, {
type: ['noencode', 'encodemany', 'encodelast'],
n: [1e6],
n: [1e7],
});

function main(conf) {
Expand Down Expand Up @@ -37,6 +37,7 @@ function main(conf) {

v8.setFlagsFromString('--allow_natives_syntax');
eval('%OptimizeFunctionOnNextCall(querystring.stringify)');
querystring.stringify(input);

bench.start();
for (var i = 0; i < n; i += 1)
Expand Down
32 changes: 22 additions & 10 deletions lib/querystring.js
Expand Up @@ -90,16 +90,13 @@ for (var i = 0; i < 256; ++i)
QueryString.escape = function(str) {
// replaces encodeURIComponent
// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4
str = '' + str;
var len = str.length;
if (typeof str !== 'string')
str += '';
var out = '';
var i, c;

if (len === 0)
return str;
var lastPos = 0;

for (i = 0; i < len; ++i) {
c = str.charCodeAt(i);
for (var i = 0; i < str.length; ++i) {
var c = str.charCodeAt(i);

// These characters do not need escaping (in order):
// ! - . _ ~
Expand All @@ -112,35 +109,50 @@ QueryString.escape = function(str) {
(c >= 0x30 && c <= 0x39) ||
(c >= 0x41 && c <= 0x5A) ||
(c >= 0x61 && c <= 0x7A)) {
out += str[i];
continue;
}

if (i - lastPos > 0)
out += str.slice(lastPos, i);

// Other ASCII characters
if (c < 0x80) {
lastPos = i + 1;
out += hexTable[c];
continue;
}

// Multi-byte characters ...
if (c < 0x800) {
lastPos = i + 1;
out += hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)];
continue;
}
if (c < 0xD800 || c >= 0xE000) {
lastPos = i + 1;
out += hexTable[0xE0 | (c >> 12)] +
hexTable[0x80 | ((c >> 6) & 0x3F)] +
hexTable[0x80 | (c & 0x3F)];
continue;
}
// Surrogate pair
++i;
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF));
var c2;
if (i < str.length)
c2 = str.charCodeAt(i) & 0x3FF;
else
c2 = 0;
lastPos = i + 1;
c = 0x10000 + (((c & 0x3FF) << 10) | c2);
out += hexTable[0xF0 | (c >> 18)] +
hexTable[0x80 | ((c >> 12) & 0x3F)] +
hexTable[0x80 | ((c >> 6) & 0x3F)] +
hexTable[0x80 | (c & 0x3F)];
}
if (lastPos === 0)
return str;
if (lastPos < str.length)
return out + str.slice(lastPos);
return out;
};

Expand Down

0 comments on commit 00638ac

Please sign in to comment.