Dan Sugalski wrote:

Okay, since this has all come up, here's the scoop from a design perspective.

Hard stuff did meet my printer at midnight, reading it onscreen twice didn't help ;-)

First:

Definition #0: A bytecode segment is a sequence of code, which is loaded into memory with no execution of such code intersparsed. So all subs, modules, whatever loaded from zig files may be one code segment, *if* the runloop wasn't entered. Or: as soon as the code is running, loading additional bytecode puts this code into a different bytecode segment.


Design Edict #1: Branches, which is any transfer of control that takes an offset, may *not* escape the current bytecode segment.

Design Edict #2: Jumps may go anywhere.

Design Edict #3: All destinations *must* be marked as such in the bytecode metadata segment. (I am officially nervous about this, as I can see a number of ways to subvert this for evil)

I would define: Jumps may go to any location aquired per set_addr call or to branch tables. Jumping somewhere else may kill your dog.

Jumping to a set_addr label is recognized already, jump tables may probably need some marker around them, so that the jump targets won't get killed by dead code elimination.


I'm only keeping jumps (and their corresponding jsr) around for nostalgic reasons, and with the vague hope they may be useful. I'm not sure about this.

They would be useful for a computed goto.


s/compreg/compile/g for($below);


The compreg op should compile the passed code ...

Design Edict #7: the compreg opcode will execute the compiled code, calling in with parrot's calling conventions. If it should return something, then it had darned well better build it and return it.

If the compile opcode has to execute the code, I would call it "eval".

But: When compile and eval are separate stages, the HL might be able to pull the compile stage out of e.g. loops. So I think keeping compiling and evaling separate makes sense.


Thanks for putting this together,
leo


Reply via email to