5 ms·
I'm actually slightly disappointed as I had just come up with the tail call optimization version as a replacement for the computed gotos since they aren't suppo
by Cieric 4y ago
I'm actually slightly disappointed as I had just come up with the tail call optimization version as a replacement for the computed gotos since they aren't supported in MSVC (I was considering making it my own first blog post).
If I could ask what made you go for a list of unions for the functions instead of just a plain array of function pointers (or a typedef'd function type)? I can't see any benefits that would be gained from using the union, but I assume I'm just missing something.
- Cieric 4y agoOh wait I see I'm mistaken, the function pointer is being used as the opcode and you're running across the instruction list with the &instrs[2], that makes more sense at least. I can't personally do that for my VM however since I'm using an existing instruction set. I'll have to give this a full read when I get off work.
- mort96 4y agoYou should absolutely write your own blog post about it! I'm sure your approach is somewhat different from mine, and different approaches to the same problem is always interesting. In a week or two everyone will have forgotten my post anyway and yours will seem fresh and interesting. Regarding the list of unions thing: The instruction stream needs to contain both the operations (the function pointer) and the operands. In a plain array of function pointers, how would a function get at its operands? For example, for `CONSTANT 15`, how do you encode the 15 if all you have is an array of function pointers? I suppose you could cast back and forth between a function pointer and an intptr_t, but I prefer having the explicit union. (EDIT: I see you figured it out already while I was writing this)
- Cieric 4y agoI'll definitely still consider it, I think I got lost in the fact that I originally made mine similar to the original version of the dispatch table. Then I just had a byte array of memory where I wrote instructions and values directly into the memory and then executed it. Stack also lived in the memory block growing downwards like a normal stack. And yeah as you said the constant function I have reads in the value from the program_counter and increments it manually. but since all values and opcodes were only bytes it didn't feel off just reading it in the same way.
- ack_complete 4y agoMSVC can sometimes be convinced to emit tail jumps from a switch() if the cases are densely packed and there is an __assume(0) on the default. Unfortunately, it also tends to encode an offset table instead of a jump table on x64, which I have not found a way to suppress.