For some bizarre reason I felt compelled to spend hours of night writing an HQ9+ interpreter. Not just any HQ9+ interpreter, I thought, but the fastest HQ9+ interpreter in the world. Is that useless, you ask? Of course it is.
Now that recent versions of GCC are freely available on x86 and AMD64 versions of Linux and Windows3, we programmers can use the same tools and code and target different platforms with the minimum of changes (and headaches!). However, those differences do accentuate themselves if you begin working closer to the metal, either because of requirements like performance or just for fun.
In this case, the distinction causing trouble was calling conventions. Regular 32-bit machines use cdecl, which is straightforward and passes parameters to functions on the stack. Newer AMD64 software use variants of fastcall, which passes some number of arguments inside registers to take advantage of the doubled register count in AMD64 over x86. To make things more complicated, Microsoft uses their own unique AMD64 calling conventions for Windows and related tools.
Part of this exercise was to abstract away the general nastiness of writing—or generating—assembly code through object-oriented design. I accomplished this through the magic of dynamic4 polymorphism. Different code emitters generating code for each platform talked directly with AsmJit, the code generation library I used, but were hidden behind interfaces from the token processor. In addition, the token processors—one with JIT and one that executed token directly—were hidden from the parser (the token generator) as well through an interface, so that I can enable or disable JIT at runtime.
Overall, this little project was a success. It isn’t exactly groundbreaking or very useful for day-to-day work, but the experience of making it was a valuable one.