Editing Efficient GOTO This edit will create a new revision. Your details (optional) Name Email (won’t be displayed; might be used for Gravatar) URL Test case details Title * Published (uncheck if you want to fiddle around before making the page public) Description (in case you feel further explanation is needed)(Markdown syntax is allowed) This jsperf is to explore options for generating JS out of luajit bytecode. https://gist.github.com/4206005#file_compiled.js Are you a spammer? (just answer the question) Preparation code Preparation code HTML (this will be inserted in the <body> of a valid HTML5 document in standards mode) (useful when testing DOM operations or including libraries) Include JavaScript libraries as follows: <script src="//cdn.ext/library.js"></script> Define setup for all tests (variables, functions, arrays or other objects that will be used in the tests) (runs before each clocked test loop, outside of the timed code region) (e.g. define local test variables, reset global variables, clear canvas, etc.) (see FAQ) function proto1(env, args, exit) { // Allocate slots for frames var f0, f1, f2, f3; // Split the code into blocks to enable jumps function _0001() { f0 = [ null, 'This', 'is', 'a', 'stream?' ]; //0001 TDUP 0 0 f1 = 1; //0002 KSHORT 1 1 f2 = env.print; //0003 GGET 2 1 ; "print" f3 = "before"; //0004 KSTR 3 2 ; "before" f2(f3); //0005 CALL 2 1 2 return _0006; } function _0006() { f2 = f0[f1]; //0006 => TGETV 2 0 1 if (!f2) //0007 ISF 2 return _0015; //0008 JMP 3 => 0015 //0009 LOOP 2 => 0015 f2 = env.print; //0010 GGET 2 1 ; "print" f3 = f0[f1]; //0011 TGETV 3 0 1 f2(f3); //0012 CALL 2 1 2 f1 = f1 + 1; //0013 ADDVN 1 1 0 ; 1 return _0006; //0014 JMP 2 => 0006 } function _0015() { f2 = env.print; //0015 => GGET 2 1 ; "print" f3 = "after"; //0016 KSTR 3 3 ; "after" f2(f3); //0017 CALL 2 1 2 exit(null, []); //0018 RET0 0 1 } // Run a little trampoline to enable the gotos var next = _0001; while (next = next()); } function proto2(env, args, exit) { // Allocate slots for frames var f0, f1, f2, f3; // Split the code into blocks to enable jumps var blocks = { _0001: function () { f0 = [ null, 'This', 'is', 'a', 'stream?' ]; //0001 TDUP 0 0 f1 = 1; //0002 KSHORT 1 1 f2 = env.print; //0003 GGET 2 1 ; "print" f3 = "before"; //0004 KSTR 3 2 ; "before" f2(f3); //0005 CALL 2 1 2 return "_0006"; }, _0006: function () { f2 = f0[f1]; //0006 => TGETV 2 0 1 if (!f2) //0007 ISF 2 return "_0015"; //0008 JMP 3 => 0015 //0009 LOOP 2 => 0015 f2 = env.print; //0010 GGET 2 1 ; "print" f3 = f0[f1]; //0011 TGETV 3 0 1 f2(f3); //0012 CALL 2 1 2 f1 = f1 + 1; //0013 ADDVN 1 1 0 ; 1 return "_0006"; //0014 JMP 2 => 0006 }, _0015: function () { f2 = env.print; //0015 => GGET 2 1 ; "print" f3 = "after"; //0016 KSTR 3 3 ; "after" f2(f3); //0017 CALL 2 1 2 exit(null, []); //0018 RET0 0 1 } }; // Run a little trampoline to enable the gotos var next = "_0001"; while (next = blocks[next]()); } function proto3(env, args, exit) { // Allocate slots for frames var f0, f1, f2, f3; var state = "0001"; main: while(true) { switch(state) { case "0001": f0 = [ null, 'This', 'is', 'a', 'stream?' ]; //0001 TDUP 0 0 f1 = 1; //0002 KSHORT 1 1 f2 = env.print; //0003 GGET 2 1 ; "print" f3 = "before"; //0004 KSTR 3 2 ; "before" f2(f3); //0005 CALL 2 1 2 state = "0006"; break; case "0006": f2 = f0[f1]; //0006 => TGETV 2 0 1 if (!f2) { //0007 ISF 2 state = "0015"; //0008 JMP 3 => 0015 break; } // no-op tracing hook //0009 LOOP 2 => 0015 f2 = env.print; //0010 GGET 2 1 ; "print" f3 = f0[f1]; //0011 TGETV 3 0 1 f2(f3); //0012 CALL 2 1 2 f1 = f1 + 1; //0013 ADDVN 1 1 0 ; 1 state = "0006"; //0014 JMP 2 => 0006 break; case "0015": f2 = env.print; //0015 => GGET 2 1 ; "print" f3 = "after"; //0016 KSTR 3 3 ; "after" f2(f3); //0017 CALL 2 1 2 exit(null, []); //0018 RET0 0 1 break main; } } } function proto4(env, args, exit) { // Allocate slots for frames var f0, f1, f2, f3; var state = "0001"; for(;;) { switch(state) { case "0001": f0 = [ null, 'This', 'is', 'a', 'stream?' ]; //0001 TDUP 0 0 f1 = 1; //0002 KSHORT 1 1 f2 = env.print; //0003 GGET 2 1 ; "print" f3 = "before"; //0004 KSTR 3 2 ; "before" f2(f3); //0005 CALL 2 1 2 state = "0006"; break; case "0006": f2 = f0[f1]; //0006 => TGETV 2 0 1 if (!f2) { //0007 ISF 2 state = "0015"; //0008 JMP 3 => 0015 break; } // no-op tracing hook //0009 LOOP 2 => 0015 f2 = env.print; //0010 GGET 2 1 ; "print" f3 = f0[f1]; //0011 TGETV 3 0 1 f2(f3); //0012 CALL 2 1 2 f1 = f1 + 1; //0013 ADDVN 1 1 0 ; 1 state = "0006"; //0014 JMP 2 => 0006 break; case "0015": f2 = env.print; //0015 => GGET 2 1 ; "print" f3 = "after"; //0016 KSTR 3 3 ; "after" f2(f3); //0017 CALL 2 1 2 return exit(null, []); //0018 RET0 0 1 } } } // Set up some global functions var _G = { print: function () { //console.log(Array.prototype.join.call(arguments, " ")); return []; } }; function onExit(err, results) { if (err) throw err; } Define teardown for all tests (runs after each clocked test loop, outside of the timed code region) (see FAQ) Code snippets to compare Test 1 Title Async (check if this is an asynchronous test) Code proto1(_G, [], onExit); Test 2 Title Async (check if this is an asynchronous test) Code proto2(_G, [], onExit); Test 3 Title Async (check if this is an asynchronous test) Code proto3(_G, [], onExit); Test 4 Title Async (check if this is an asynchronous test) Code proto4(_G, [], onExit);