Skip to content

Commit

Permalink
Bring try/catch into invoke.
Browse files Browse the repository at this point in the history
Left it in its own little function because it seemed to be a wee bit
faster there still. `try/catch` used to prevent JIT compilation which is
why it was in its own function to begin with, it would otherwise cause
`invoke` to be uncompiled and terrible slow.

 % node benchmark/increment/call.js
_cadence call 1 x 5,225,931 ops/sec ±2.80% (90 runs sampled)
 cadence call 1 x 5,160,580 ops/sec ±2.94% (90 runs sampled)
_cadence call 2 x 5,210,175 ops/sec ±2.59% (92 runs sampled)
 cadence call 2 x 5,270,328 ops/sec ±0.68% (94 runs sampled)
_cadence call 3 x 5,288,174 ops/sec ±0.64% (94 runs sampled)
 cadence call 3 x 5,153,411 ops/sec ±2.18% (93 runs sampled)
_cadence call 4 x 5,256,624 ops/sec ±0.74% (91 runs sampled)
 cadence call 4 x 5,214,441 ops/sec ±1.99% (94 runs sampled)
Fastest is _cadence call 3, cadence call 2,_cadence call 4, cadence call 4,_cadence call 2, cadence call 1
 % node benchmark/increment/call.js
_cadence call 1 x 5,176,786 ops/sec ±3.14% (92 runs sampled)
 cadence call 1 x 5,178,754 ops/sec ±2.93% (91 runs sampled)
_cadence call 2 x 5,231,882 ops/sec ±2.60% (94 runs sampled)
 cadence call 2 x 5,337,209 ops/sec ±0.80% (94 runs sampled)
_cadence call 3 x 5,288,183 ops/sec ±0.60% (93 runs sampled)
 cadence call 3 x 5,220,239 ops/sec ±2.19% (90 runs sampled)
_cadence call 4 x 5,258,038 ops/sec ±1.09% (95 runs sampled)
 cadence call 4 x 5,211,841 ops/sec ±2.23% (94 runs sampled)
Fastest is  cadence call 2,_cadence call 2
  • Loading branch information
flatheadmill committed Nov 26, 2018
1 parent 13f1d6a commit f103820
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 44 deletions.
51 changes: 28 additions & 23 deletions _cadence.js
@@ -1,4 +1,4 @@
var stack = [], push = [].push, JUMP = {}
var stack = [], JUMP = {}

function Cadence (parent, self, steps, vargs, callback, loop, cadence) {
this.parent = parent
Expand Down Expand Up @@ -217,7 +217,6 @@ function invoke (cadence) {

if (ret.length === 2) {
cadence.errors.push(ret[1])
cadence.vargs = vargs
cadence.sync = true
} else {
// The only one that could be removed if we where to invoke cadences
Expand Down Expand Up @@ -260,14 +259,14 @@ async.continue = { jump: JUMP, index: 0, break: false, immediate: false }
async.break = { jump: JUMP, index: Infinity, break: true, immediate: false }
async.return = { jump: JUMP, index: Infinity, break: true, immediate: true }

function variadic (f, self) {
function variadic (f) {
return function () {
var I = arguments.length
var vargs = new Array
for (var i = 0; i < I; i++) {
vargs.push(arguments[i])
}
return f.call(self, vargs)
return f(vargs)
}
}

Expand All @@ -280,7 +279,7 @@ async.loop = variadic(function (steps) {
continue: { jump: JUMP, index: 0, break: false, cadence: looper, immediate: false },
break: { jump: JUMP, index: Infinity, break: true, cadence: looper, immediate: false }
}
}, async)
})

async.block = variadic(function (steps) {
var loop
Expand All @@ -289,7 +288,7 @@ async.block = variadic(function (steps) {
return [ loop.break ].concat(vargs)
}))
return loop = async.loop.apply(async, steps)
}, async)
})

async.forEach = variadic(function (steps) {
var loop, vargs = steps.shift(), array = vargs.shift(), index = -1
Expand All @@ -298,8 +297,8 @@ async.forEach = variadic(function (steps) {
if (index === array.length) return [ loop.break ].concat(vargs)
return [ array[index], index ].concat(vargs)
}))
return loop = this.loop.apply(this, steps)
}, async)
return loop = async.loop.apply(this, steps)
})

async.map = variadic(function (steps) {
var loop, vargs = steps.shift(), array = vargs.shift(), index = -1, gather = []
Expand All @@ -311,8 +310,10 @@ async.map = variadic(function (steps) {
steps.push(variadic(function (vargs) {
gather.push.apply(gather, vargs)
}))
return loop = this.loop.apply(this, steps)
}, async)
return loop = async.loop.apply(this, steps)
})

var builders = []

function cadence () {
var I = arguments.length
Expand All @@ -330,10 +331,10 @@ function cadence () {
invoke(new Cadence(null, this, steps, vargs, arguments[i], false, null))
}
var f
// Preserving arity costs next to nothing; the call to `execute` in
// these functions will be inlined. The airty function itself will never
// be inlined because it is in a different context than that of our
// dear user, but it will be compiled.
// Preserving arity costs next to nothing; the call to `execute` in these
// functions will be inlined. The airty function itself will never be
// inlined because it is in a different context than that of our dear user,
// but it will be compiled.
switch (steps[0].length) {
case 0:
f = function () { execute.apply(this, arguments) }
Expand All @@ -351,16 +352,20 @@ function cadence () {
f = function (one, two, three, four) { execute.apply(this, arguments) }
break
default:
// Avert your eyes if you're squeamish.
var args = []
for (var i = 0, I = steps[0].length; i < I; i++) {
args[i] = '_' + i
while (builders.length < steps[0].length - 4) {
var args = []
for (var i = 0, I = builders.length + 5; i < I; i++) {
args[i] = '_' + i
}
builders.push(new Function (' \n\
return function (execute) { \n\
return function (' + args.join(',') + ') { \n\
execute.apply(this, arguments) \n\
} \n\
} \n\
')())
}
f = (new Function('execute', ' \n\
return function (' + args.join(',') + ') { \n\
execute.apply(this, arguments) \n\
} \n\
'))(execute)
f = builders[steps[0].length - 5](execute)
}

f.toString = function () { return steps[0].toString() }
Expand Down
31 changes: 10 additions & 21 deletions cadence.js
Expand Up @@ -78,15 +78,6 @@ function createCallback (cadence) {
}
}

function call (fn, self, vargs) {
try {
var ret = fn.apply(self, vargs)
} catch (e) {
return [ ret, e ]
}
return [ ret ]
}

function invoke (cadence) {
var vargs, fn
for (;;) {
Expand Down Expand Up @@ -210,15 +201,11 @@ function invoke (cadence) {

stack.push(cadence)

var ret = call(fn, cadence.self, vargs)
// ^^^^

stack.pop()

if (ret.length === 2) {
cadence.errors.push(ret[1])
cadence.sync = true
} else {
try {
var ret = fn.apply(cadence.self, vargs)
if (ret !== void(0)) {
cadence.vargs = Array.isArray(ret) ? ret : [ ret ]
}
// The only one that could be removed if we where to invoke cadences
// directly and immediately when created. It would change loop
// labeling so that the loop label was always passed in as a final
Expand All @@ -229,11 +216,13 @@ function invoke (cadence) {
while (cadence.cadences.length != 0) {
invoke(cadence.cadences.shift())
}
if (ret[0] !== void(0)) {
cadence.vargs = Array.isArray(ret[0]) ? ret[0] : [ ret[0] ]
}
} catch (error) {
cadence.errors.push(error)
cadence.sync = true
}

stack.pop()

if (!cadence.sync) {
cadence.waiting = true
break
Expand Down

0 comments on commit f103820

Please sign in to comment.