RHS: I've been working on a package to examine and modify the bytecodes for a proc. Since I've actually gotten something working, I figured its time I put up a link to what I've done so far. The actual code (which is a combination of Tcl and C) can be found at [L1 ] where the rest of the things I've been working on are located.
What is it?
The general idea of the package is to allow one to get the bytecodes for a procedure, and then modify them. The current code implements:
::bytecode::get procname
::bytecode::setExceptionRanges procname ranges
I've also used the forward compatible dict code from forward-compatible dict, because it made the output from the get command much easier to understand when using dicts.
As a note, the code is full of memory leaks. The two main places I'm aware of where there are leaks are:
To Do
Once one can set all 4 of the above (the currently setable exception ranges being the 4th), I believe it will be possible to write a command that can define a proc from scratch using bytecodes, along the lines of:
::bytecode::byteproc args extraCompiledLocals compiledLiterals exceptionRanges byteCodes
Where:
proc testme {} { set retval 0 for {set i 0} {$i < 10} {incr i} { for {set j 0} {$j < 10} {incr j} { incr retval break } } return $retval }
Would be
::bytecode::byteproc testme {} { 0 {Type scalar Name retval} 1 {Type scalar Name i} 2 {Type scalar Name j} } { 0 1 1 10 2 {} } { 0 {Level 1 Type loop PC {12 37} Continue 39 Break 50} 1 {Level 1 Type loop PC {39 41} Continue -1 Break 50} 2 {Level 2 Type loop PC {19 23} Continue 25 Break 36} 3 {Level 2 Type loop PC {25 27} Continue -1 Break 36} } { {push1 0} {storeScalar1 0} {pop} {push1 0} {storeScalar1 1} {pop } {jump1 33} {push1 0} {storeScalar1 2} {pop } {jump1 12} {incrScalar1Imm 0 1} {pop} {break} {pop} {incrScalar1Imm 2 1} {pop} {loadScalar1 2} {push1 1} {lt} {jumpTrue1 -15} {push1 2} {pop} {incrScalar1Imm 1 1} {pop} {loadScalar1 1} {push1 1} {lt} {jumpTrue1 -36} {push1 2} {pop} {loadScalar1 0} {done} {done} }
As a note, if the 3rd exception (lindex 2) is changed from break 36 to break 50, breaks in the inner for loop now break the outter loop also, so proc returns 1 instead of 10 (that actuall the test I use for the setExceptionRange command).