apfelmus wrote:
Note that even currently, your operations cannot be strict in the address a label refers to because this may be determined later than the first use of the label. In other words, your example codefac = do
[...]
(1) jmp loopTest
[...]
(2) loopTest @@ cmp ecx (0 :: Word32)
[...]
already shows that the function jmp that generates a jmp-instruction may not be strict in the position it jumps to as the address behind loopTest is only known later at line (2).
When generating code for (1), the label loopTest is used as an index into a map, to see whether there's a code position associated with it. If it is, the code position is used to compute the jump offset for the jmp instruction, if not (as in this example), a dummy value is placed in the code buffer, and Harpy remembers this position to be patched later on. At (2), the label is defined, and this leads to patching all instructions that have been emitted before this definition.
So, yes, the code position is only used after the definition of the label. But the "look up in a map"-part makes the jmp operation strict in the label parameter.
We could omit the map, and just remember where to patch the code, but then we'd need to call explicitly some function after code generation that does the patching. We had implemented this, but found the current solution easier to use, since backpatching is completely automatic and hidden from the user.
However, this is just a description of the current implementation, not an argument that there's no better implementation. Probably there is, maybe using the binary package.
Also, the explicit declaration of labels has an inherent safety problem.
[...]
Declaring a label (via f.i.) loopStart <- mul exc at it's instruction doesn't have this problem.
This looks quite elegant, I'll think about it...
Furthermore, having to call 'ensureBufferSize 160' is very strange for this is data that can be calculated automatically.
As I wrote at haskell-cafe, we require this only for performance reasons, to keep buffer overflow checks as seldom as possible. But there might be better ways to do this.
I also think that having liftIO in the CodeGen-monad is plain wrong. I mean, CodeGen is a monad that generates code without any execution taking place. The execution part is already handled by runCodeGen. Having liftIO means that arbitrary Haskell programs can be intertwined with assembly generation and I doubt that you want that.
Feel free to doubt, but this is exactly what we want. :-)Also, note that runCodeGen runs the code _generation_, executing the generated code is done _within_ the CodeGen monad via the functions generated by callDecl (or the predefined functions in the Harpy.Call module). This is even more intertwined, but intentional.
Of course, again a different design is possible, making runCodeGen return a binary code object, that can be called from the IO monad. But then, the user has to care about releasing code buffers, and not to have unevaluated closures having code pointers to already released run-time generated code.
Kind regards, Dirk
smime.p7s
Description: S/MIME Cryptographic Signature
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell