At 10:10 AM +0200 10/25/03, Leopold Toetsch wrote:
Dan Sugalski <[EMAIL PROTECTED]> wrote:
   "jsr xxxx" where xxxx is an immediate address rather than a register
   generates bad code.

C<jsr> takes an absolute bytecode address, which IMHO never can be an immediate integer. The op should be defined as jsr(invar INT).

Oh, it certainly can be an absolute address, if you know what the address is when you're generating the code. Assuming fixed-address bytecode segments, of course, but I think we're not pondering GC possibly moving bytecode. (I had actually considered it, but decided that was a bit much even for me :)


That's what actually triggered all this--the forth compiler generates code on the fly. There are a set of base words that are their own chunks of assembly, then there are the user-defined words which get their bytecode generated on the fly by creating little pieces of assembly that jsr into the base words.

2drop, for example, drops the two words on the top of the stack and is really just "drop drop", and can be build from existing words. (drop, in this case) The generated code for the word *should* look like:

   jsr .drop
   jsr .drop
   ret

where drop is the address of the drop code. (I use a real value rather than the constant, but this is for illustrative purposes) This doesn't work now, for lack of immediate jsrs, and the code is instead

    set .scratchI, .drop
    jsr .scratchI
    set .scratchI, .drop
    jsr .scratchI
    ret

To snag in the other message at the same time, I am aware of the issues involved in crossing packfile segments with this. (You'll note some mildly vicious hackery in the code because of this) That's something we need to address--I'm OK both with different bytecode segments sharing a constant table, as well as mandating that new segments may, if given the appropriate flags at creation time, can share the existing constant segment. (FWIW, the code as it stands does, even with me doing Mildly Evil Things, work and handle the nasty segment crossing. Kudos are in order all around because of that. :)

I *don't* want to use the full-on calling conventions here, because they are unnecessary, and arguably downright incorrect for forth--when you create new words you bind the current definition, not the new definition. (I think. I might be wrong about that, in which case Plan B may be in order) The local calling conventions are also very different, and I'd rather not use them except when I have to. (PDD03's pretty clear that the calling conventions don't have to be followed for internal calls)

Being able to do what I'm doing is very useful for languages with lightweight normal calling needs and dynamic compilation. (Like, say, Forth) I'm willing to lose the capability if it just doesn't work out, but I'd rather not if we can avoid it.
--
Dan


--------------------------------------"it's like this"-------------------
Dan Sugalski                          even samurai
[EMAIL PROTECTED]                         have teddy bears and even
                                      teddy bears get drunk

Reply via email to