javascriptperformanceindexedindirectionjump-table

Fastest way to call a javascript function (or method) via a lookup table of function names?


I am simulating an 8-bit microprocessor with JavaScript. I have stored each opcode function name in an array, and call each of the 256 functions relative to the opcode read from my virtual memory, as follows:

this.OP[opcode] = 'this.LDAA()';
eval(this.OP[opcode]);

I have recently altered my code to get rid of the eval() as below:

this.OP[opcode] = 'LDAA';
this[this.OP[opcode]]();

In Mac Safari there is no discernible speed difference between either of the above, which surprised me. I thought the latter would be faster but my virtual clock speed is about the same for both (presently peaking at 4MHz).

As there appears to be no speed penalty by using indexed method calls compared with using eval() I wish to also update my virtual memory system, but I am having a mental block about the syntax to use.

To write a byte I have:

RAM = {
    write : [],
    setup : function() {
        this.write[addr] = "this.simpleWrite(addr,byte)";
    },

    writeByte : function(addr,byte) { 
        eval(this.write[addr]);
    },

    simpleWrite : function(addr,byte) { 
        this.memory[addr] = byte;
    },
};

RAM.writeByte( someAddress, someValue );

I am using this indexed, indirect method so I can map devices into the address range and place breakpoints and watchpoints as required which all intercept memory reads and writes - maximising performance.

Any suggestions on how to lose the eval's whilst maintaining data throughput?

I want to map external methods into the indirection array, and be able to pass parameters (values to write). So that whatever piece of virtual hardware is accessing the virtual memory using a common interface, other bits of virtual hardware can intercept the process and monitor or alter values if necessary.


Solution

  • The alternative to using the eval approach detailed in the question:

    RAM = {
        memory : [],
        write : [],
        setup : function() {
            for (var addr = start; addr < length; ++addr) {
                this.write[addr] = 
                    function(a) { 
                        function(byte) { 
                            RAM.memory[a] = byte 
                        }
                    }(addr);
                }
            }
        }
    RAM.setup();
    RAM.write[validAddress](byteValue);
    

    This is about 5% faster than using the initial eval approach (in Mac Safari). It is also tidier and removes the use of eval. The complexity of the function definition within the for...loop is due to the scope of the variable addr which is created local to the setup function. A pointer to this variable would be passed to the inner function if used directly and when the loop completes all array elements would then have the same 'address' being the value of addr at the end of the loop (start+length). So, I create a new local variable (a), which is a constant, on each iteration of the loop via an outer function and this value is used (via a pointer) within each inner function.

    Also note that I access the memory array using the object name (RAM) rather than .this because other objects may access the inner method indirectly and cause .this to reference the calling object. Naming the object directly solves this issue.

    For a more detailed example and explanation about creating functions within loops see callbacks in loops.