lib: micro-optimize url.resolve()
authorBen Noordhuis <info@bnoordhuis.nl>
Fri, 19 Dec 2014 22:46:37 +0000 (23:46 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Sat, 20 Dec 2014 20:33:52 +0000 (21:33 +0100)
Replace the call to Array#splice() with a faster open-coded version
that creates less garbage.

Add a new benchmark to prove it.  With the change applied, it scores
about 5% higher and that is nothing to sneeze at.

PR-URL: https://github.com/iojs/io.js/pull/184
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
benchmark/url/url-resolve.js [new file with mode: 0644]
lib/url.js

diff --git a/benchmark/url/url-resolve.js b/benchmark/url/url-resolve.js
new file mode 100644 (file)
index 0000000..5f6c1f7
--- /dev/null
@@ -0,0 +1,31 @@
+var common = require('../common.js');
+var url = require('url');
+var v8 = require('v8');
+
+var bench = common.createBenchmark(main, {
+  type: ['one'],
+  n: [1e5],
+});
+
+function main(conf) {
+  var type = conf.type;
+  var n = conf.n | 0;
+
+  var inputs = {
+    one: ['http://example.com/', '../../../../../etc/passwd'],
+  };
+  var input = inputs[type] || [];
+
+  // Force-optimize url.resolve() so that the benchmark doesn't get
+  // disrupted by the optimizer kicking in halfway through.
+  for (var name in inputs)
+    url.resolve(inputs[name][0], inputs[name][1]);
+
+  v8.setFlagsFromString('--allow_natives_syntax');
+  eval('%OptimizeFunctionOnNextCall(url.resolve)');
+
+  bench.start();
+  for (var i = 0; i < n; i += 1)
+    url.resolve(input[0], input[1]);
+  bench.end(n);
+}
index 2231ea0..2d9d436 100644 (file)
@@ -670,12 +670,12 @@ Url.prototype.resolveObject = function(relative) {
   for (var i = srcPath.length; i >= 0; i--) {
     last = srcPath[i];
     if (last === '.') {
-      srcPath.splice(i, 1);
+      spliceOne(srcPath, i);
     } else if (last === '..') {
-      srcPath.splice(i, 1);
+      spliceOne(srcPath, i);
       up++;
     } else if (up) {
-      srcPath.splice(i, 1);
+      spliceOne(srcPath, i);
       up--;
     }
   }
@@ -750,3 +750,10 @@ Url.prototype.parseHost = function() {
   }
   if (host) this.hostname = host;
 };
+
+// About 1.5x faster than the two-arg version of Array#splice().
+function spliceOne(list, index) {
+  for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
+    list[i] = list[k];
+  list.pop();
+}