<story><title>TinyVM: A lightweight, fast virtual machine in &lt; 500 lines of ANSI C</title><url>https://github.com/GenTiradentes/tinyvm</url></story><parent_chain><item><author>anon_comenter9</author><text>Unless this is relying on the compiler optimizing this, the dispatch looks to be not good&lt;p&gt;if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == MOV)	&lt;i&gt;arg0 = &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == PUSH) stack_push(vm-&amp;#62;pStack, arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == POP)	stack_pop(vm-&amp;#62;pStack, arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == INC)	++(&lt;i&gt;arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == DEC)	--(&lt;/i&gt;arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == ADD)	&lt;i&gt;arg0 += &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == SUB)	&lt;i&gt;arg0 -= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == MUL)	&lt;i&gt;arg0 &lt;/i&gt;= &lt;i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == DIV)	&lt;/i&gt;arg0 /= &lt;i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == MOD)	vm-&amp;#62;pMemory-&amp;#62;remainder = &lt;/i&gt;arg0 % &lt;i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == REM)	&lt;/i&gt;arg0 = vm-&amp;#62;pMemory-&amp;#62;remainder;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == NOT)	&lt;i&gt;arg0 = ~(&lt;/i&gt;arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == XOR)	&lt;i&gt;arg0 ^= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == OR)	&lt;i&gt;arg0 |= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == AND)	&lt;i&gt;arg0 &amp;#38;= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == SHL)	&lt;i&gt;arg0 &amp;#60;&amp;#60;= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == SHR)	&lt;i&gt;arg0 &amp;#62;&amp;#62;= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == CMP)	vm-&amp;#62;pMemory-&amp;#62;FLAGS = ((&lt;i&gt;arg0 == &lt;/i&gt;arg1) | (&lt;i&gt;arg0 &amp;#62; &lt;/i&gt;arg1) &amp;#60;&amp;#60; 1);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JMP)	instr_idx = &lt;i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JE
			&amp;#38;&amp;#38; (vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x1)) 	instr_idx = &lt;/i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JNE
			&amp;#38;&amp;#38; !(vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x1))	instr_idx = &lt;i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JG
			&amp;#38;&amp;#38; (vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x2)) 	instr_idx = &lt;/i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JGE
			&amp;#38;&amp;#38; (vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x3))	instr_idx = &lt;i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JL
			&amp;#38;&amp;#38; !(vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x3))	instr_idx = &lt;/i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JLE
			&amp;#38;&amp;#38; !(vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x2))	instr_idx = *arg0 - 1;</text></item></parent_chain><comment><author>jws</author><text>Update: I changed it to a switch statement. The euler1 program went from 0.081s to 0.091s with gcc on a core i3.&lt;p&gt;The cascading &lt;i&gt;if&lt;/i&gt; statements are indeed faster than a switch.&lt;p&gt;EOU - original comment follows…&lt;p&gt;Without the benefit of profiling, I can suggest it may not be as bad as it looks.&lt;p&gt;The relative frequency of the opcodes could make this faster than the switch. See MOV, PUSH, POP in the front? Theses likely have tiny, inline implementations and are also probably a large percentage of the opcodes implemented. They may all fit in the same cache line and give the pipelines on deep pipeline, branch predicting machines lots of good stuff to work on.&lt;p&gt;Likewise, the infrequently occurring opcode comparisons in the back part of the statement, by definition, are almost always false, which should tell the branch predictors which way to go to again keep the pipelines full.&lt;p&gt;A switch on the other hand is pretty much a guaranteed pipeline flush.&lt;p&gt;But… if you asked me to code this control structure without being able to profile and to get it fast the first time… I&apos;d use a &lt;i&gt;switch&lt;/i&gt;. (well, maybe with a couple &lt;i&gt;if&lt;/i&gt; statements out front if I knew I had a heavily lopsided distribution.)&lt;p&gt;Then if I&apos;d go reread that article that came by HN a couple weeks ago and turn the control structure inside out and see how much better it was.</text></comment>
<story><title>TinyVM: A lightweight, fast virtual machine in &lt; 500 lines of ANSI C</title><url>https://github.com/GenTiradentes/tinyvm</url></story><parent_chain><item><author>anon_comenter9</author><text>Unless this is relying on the compiler optimizing this, the dispatch looks to be not good&lt;p&gt;if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == MOV)	&lt;i&gt;arg0 = &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == PUSH) stack_push(vm-&amp;#62;pStack, arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == POP)	stack_pop(vm-&amp;#62;pStack, arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == INC)	++(&lt;i&gt;arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == DEC)	--(&lt;/i&gt;arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == ADD)	&lt;i&gt;arg0 += &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == SUB)	&lt;i&gt;arg0 -= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == MUL)	&lt;i&gt;arg0 &lt;/i&gt;= &lt;i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == DIV)	&lt;/i&gt;arg0 /= &lt;i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == MOD)	vm-&amp;#62;pMemory-&amp;#62;remainder = &lt;/i&gt;arg0 % &lt;i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == REM)	&lt;/i&gt;arg0 = vm-&amp;#62;pMemory-&amp;#62;remainder;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == NOT)	&lt;i&gt;arg0 = ~(&lt;/i&gt;arg0);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == XOR)	&lt;i&gt;arg0 ^= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == OR)	&lt;i&gt;arg0 |= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == AND)	&lt;i&gt;arg0 &amp;#38;= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == SHL)	&lt;i&gt;arg0 &amp;#60;&amp;#60;= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == SHR)	&lt;i&gt;arg0 &amp;#62;&amp;#62;= &lt;/i&gt;arg1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == CMP)	vm-&amp;#62;pMemory-&amp;#62;FLAGS = ((&lt;i&gt;arg0 == &lt;/i&gt;arg1) | (&lt;i&gt;arg0 &amp;#62; &lt;/i&gt;arg1) &amp;#60;&amp;#60; 1);
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JMP)	instr_idx = &lt;i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JE
			&amp;#38;&amp;#38; (vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x1)) 	instr_idx = &lt;/i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JNE
			&amp;#38;&amp;#38; !(vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x1))	instr_idx = &lt;i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JG
			&amp;#38;&amp;#38; (vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x2)) 	instr_idx = &lt;/i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JGE
			&amp;#38;&amp;#38; (vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x3))	instr_idx = &lt;i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JL
			&amp;#38;&amp;#38; !(vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x3))	instr_idx = &lt;/i&gt;arg0 - 1;
		else if(vm-&amp;#62;pProgram-&amp;#62;instr[instr_idx] == JLE
			&amp;#38;&amp;#38; !(vm-&amp;#62;pMemory-&amp;#62;FLAGS &amp;#38; 0x2))	instr_idx = *arg0 - 1;</text></item></parent_chain><comment><author>teyc</author><text>For the benefit of those who don&apos;t understand this, have a look at &lt;a href=&quot;http://en.wikipedia.org/wiki/Threaded_code&quot; rel=&quot;nofollow&quot;&gt;http://en.wikipedia.org/wiki/Threaded_code&lt;/a&gt; where it explains the different ways one can process byte codes.&lt;p&gt;The key issue here is that the efficiency of dispatch loop determines the performance of a VM.</text></comment>