Skip to content

Instantly share code, notes, and snippets.

@bjouhier
Last active December 17, 2015 05:08
Show Gist options
  • Save bjouhier/5555142 to your computer and use it in GitHub Desktop.
Save bjouhier/5555142 to your computer and use it in GitHub Desktop.
Demonstrates crash with V8 generators
function isGenerator(val) {
return Object.prototype.toString.call(val) === "[object Generator]";
}
var PENDING = {};
function run(fn, args, idx) {
var cb = args[idx],
g;
function resume(err, val) {
while (g) {
try {
val = err ? g.
throw (err) : g.send(val);
val = val.done ? undefined : val.value;
err = null;
// if we get PENDING, the current call completed with a pending I/O
// resume will be called again when the I/O completes. So just save the context and return here.
if (val === PENDING) {
return;
}
// if we get [PENDING, e, r], the current call invoked its callback synchronously
// we just loop to send/throw what the callback gave us.
if (val && val[0] === PENDING) {
err = val[1];
val = val[2];
}
// else, if g yielded a value which is not a generator, g is done.
// so we unwind it we send val to the parent generator (or through cb if we are at the top)
else if (!isGenerator(val)) {
//g.close();
g = g.prev;
}
// else, we got a new generator which means that g called another generator function
// the new generator become current and we loop with g.send(undefined) (equiv to g.next())
else {
val.prev = g;
g = val;
val = undefined;
}
} catch (ex) {
// the send/throw call failed.
// we unwind the current generator and we rethrow into the parent generator (or through cb if at the top)
//g.close();
g = g.prev;
err = makeError(ex);
val = undefined;
}
}
// we have exhausted the stack of generators.
// return the result or error through the callback.
try {
cb(err, val);
} catch (ex) {
trap(ex);
}
}
// set resume as the new callback
args[idx] = resume;
// call fn to get the initial generator
g = fn.apply(this, args);
// start the resume loop
resume();
}
function create(fn, idx) {
function F() {
//if (arguments[idx] == null) return future.call(this, F, arguments, idx);
return run.call(this, fn, arguments, idx);
};
// Memoize the original function for fast passing later
F.gstreamlineFunction = fn;
return F;
}
function invoke(that, fn, args, idx) {
// Resolve the function to be called
if (typeof fn !== 'function') {
if (typeof that === 'function' && that.gstreamlineFunction && fn === 'call') {
return that.gstreamlineFunction.apply(args[0], args.slice(1));
}
fn = that[fn];
}
// If we're waiting on a fstreamline.create function we can just call it directly instead
if (fn.gstreamlineFunction) return fn.gstreamlineFunction.apply(that, args);
// Set things up so that call returns:
// * PENDING if it completes with a pending I/O (and cb will be called later)
// * [PENDING, e, r] if the callback is called synchronously.
var result = PENDING,
sync = true;
var cb = args[idx];
args[idx] = function(e, r) {
if (sync) {
result = [PENDING, e, r];
} else {
cb(e, r);
}
}
fn.apply(that, args);
sync = false;
return result;
}
function fib(n) {
return n <= 1 ? 1 : fib(n - 1) + fib(n - 2);
}
var bench = create(function *bench(prefix, n, loop, modulo, asyncFn, _) {
var fibo_ = create(fibo, 0);
var count = 0;
function *fibo(_, nn) {
if (modulo && count++ % modulo === 0)(yield invoke(null, asyncFn, [_], 0));
if (nn <= 1) yield(1);
yield((yield fibo(_, nn - 1)) + (yield fibo(_, nn - 2)));
}
var expected = fib(n);
var t0 = Date.now();
for (var i = 0; i < loop; i++) {
var got = (yield fibo(_, n));
if (got !== expected) throw new Error("bench failed: got " + got + ', expected ' + expected);
}
var tabs = (prefix.length < 7) ? '\t\t' : '\t';
console.log(prefix + ':' + tabs + (Date.now() - t0) + "ms");
yield(count);
}, 5);
bench("generators", 25, 1, 3, setImmediate, function(err) {
if (err) throw err;
console.log("BENCH DONE");
})
@wingo
Copy link

wingo commented May 13, 2013

Fixed, and updated my node mirror. Thanks for the report. If you find something else, please use v8's issue tracker; thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment