Bytecode disassembly command, introduced in [Tcl 8.5]. : '''tcl::unsupported::disassemble proc''' ''procName'' : '''tcl::unsupported::disassemble lambda''' ''lambdaTerm'' : '''tcl::unsupported::disassemble script''' ''script'' : '''tcl::unsupported::disassemble method''' ''class method'' : '''tcl::unsupported::disassemble objmethod''' ''object method'' Love you husband **Notes** It's unfortunately not at all compatible with the [assemble] command; the formats are quite different (though the opcodes themselves are the same). Not present in [safe] interpreters. This command was developed during the [Fourteenth Annual Tcl/Tk Conference (2007)]. See also [dis2asm] for a converter from [disassemble] output to [assemble] input. **Example Output/Use** ====== % proc foo {x} { for {set y 0} {$y < $x} {incr y} { puts $x,$y } } % tcl::unsupported::disassemble proc foo ByteCode 0x0x9a2ec58, refCt 1, epoch 1, interp 0x0x9a377d8 (epoch 1) Source "\n for {set y 0} {$y < $x} {incr y} {\n puts $x,$y" Cmds 4, src 61, inst 43, litObjs 4, aux 0, stkDepth 4, code/src 0.00 Proc 0x0x9a48f70, refCt 1, args 1, compiled locals 2 slot 0, scalar, arg, "x" slot 1, scalar, "y" Exception ranges 2, depth 1: 0: level 0, loop, pc 7-18, continue 20, break 40 1: level 0, loop, pc 20-31, continue -1, break 40 Commands 4: 1: pc 0-41, src 4-59 2: pc 0-3, src 9-15 3: pc 7-18, src 45-54 4: pc 20-31, src 29-34 Command 1: "for {set y 0} {$y < $x} {incr y} {\n puts $x,$y\n " Command 2: "set y 0" (0) push1 0 # "0" (2) storeScalar1 %v1 # var "y" (4) pop (5) jump1 +28 # pc 33 Command 3: "puts $x,$y" (7) push1 1 # "puts" (9) loadScalar1 %v0 # var "x" (11) push1 2 # "," (13) loadScalar1 %v1 # var "y" (15) concat1 3 (17) invokeStk1 2 (19) pop Command 4: "incr y" (20) startCommand +12 1 # next cmd at pc 32 (29) incrScalar1Imm %v1 +1 # var "y" (32) pop (33) loadScalar1 %v1 # var "y" (35) loadScalar1 %v0 # var "x" (37) lt (38) jumpTrue1 -31 # pc 7 (40) push1 3 # "" (42) done ====== ---- [DKF]: I'm working (currently it's experimental) on a disassembler that produces output suitable for being consumed by scripts. I'm preliminarily calling it `getbytecode`, though I'm not very happy with that name! With it, I can do this: ====== # inspired by http://blog.fairchild.dk/2013/06/automagical-asm-control-flow-arrow-annotation/ proc ::tcl::unsupported::controlflow {type args} { # Pass the arguments through to the underlying bytecode retrieval system set dis [uplevel 1 [list tcl::unsupported::getbytecode $type {*}$args]] set charmap { {} " " {d u} "\u2502" {l r} "\u2500" {r u} "\u2514" {d r} "\u250c" {d l r u} "\u253c" {l r x} "\u25ba" {l r u} "\u2534" {d l r} "\u252c" } # Build the collection of jumps set jumps {} set prefix {0 {} 1 {}} dict for {from inst} [dict get $dis instructions] { foreach argument [lrange $inst 1 end] { if {[regexp {^pc (\d+) \(.*\)$} $argument -> to]} { lappend jumps [list $from $to [llength $jumps]] dict set prefix [dict size $prefix] {} } elseif {[regexp {^\?(\d+)$} $argument -> auxIdx]} { set aux [lindex [dict get $dis auxiliary] $auxIdx] if {[dict get $aux name] eq "JumptableInfo"} { # Doesn't scale very well... dict for {str offset} [dict get $aux mapping] { lappend jumps [list $from [expr {$from+$offset}] \ [llength $jumps]] dict set prefix [dict size $prefix] {} } } } } } set alen [string length $from] # Optimize the apparent depths of non-overlapping jumps/loops for {set pi -1;set i 0} {[set j $i] < [llength $jumps]} {incr i} { lassign [lindex $jumps $i] from to idx if {$idx <= $pi} continue {set pi $idx} set max [expr {max($from, $to)}] while {[incr j] < [llength $jumps]} { lassign [lindex $jumps $j] f2 t2 i2 if {$i2 > $idx && $max < min($f2, $t2)} { lset jumps $j 2 $idx lassign [lindex $jumps $j] from to idx set max [expr {max($from, $to)}] } } } set indices [lsort -integer -unique [lmap j $jumps {lindex $j 2}]] for {set i [llength $jumps]} {[incr i -1] >= 0} {} { if {$i in $indices} continue for {set j 0} {$j < [llength $jumps]} {incr j} { if {[lindex $jumps $j 2] > $i} { lset jumps $j 2 [expr {[lindex $jumps $j 2] - 1}] } } dict unset prefix [expr {[dict size $prefix]-1}] } # Print the output dict for {addr inst} [dict get $dis instructions] { array set outl $prefix set len [dict size $prefix] foreach jump $jumps { lassign $jump from to i # Reverse the order; looks better set i [expr {$len - $i - 2}] if {$from == $addr} { lappend outl($i) [lindex "u d" [expr {$from<$to}]] "r" while {[incr i] < $len} { lappend outl($i) "l" "r" } } elseif {$to == $addr} { lappend outl($i) [lindex "u d" [expr {$from>$to}]] "r" while {[incr i] < $len} { lappend outl($i) "l" "r" } lappend outl([incr i -1]) "x" } elseif {$from<$addr && $to>$addr || $from>$addr && $to<$addr} { lappend outl($i) "u" "d" } } puts [format "%s %*d %s" [join [lmap n [dict keys $prefix] { dict get $charmap [lsort -unique $outl($n)] }] ""] $alen $addr $inst] } } ====== Applied to itself, I get this output: <>Output ====== 0 push1 @0 2 push1 @1 4 push1 @2 6 loadScalar1 %0 8 list 2 13 loadScalar1 %1 15 listConcat 16 invokeStk1 3 18 storeScalar1 %2 20 pop 21 push1 @3 23 storeScalar1 %3 25 pop 26 push1 @4 28 storeScalar1 %4 30 pop 31 push1 @5 33 storeScalar1 %5 35 pop 36 loadScalar1 %2 38 push1 @6 40 dictGet 1 45 beginCatch4 0 50 dictFirst %46 ┌─ 55 jumpTrue4 {pc 332 (277)} ┌───────┼► 60 storeScalar1 %6 │ │ 62 pop │ │ 63 storeScalar1 %7 │ │ 65 pop │ │ 66 loadScalar1 %7 │ │ 68 listRangeImm .1 .end │ │ 77 storeScalar1 %47 │ │ 79 pop │ │ 80 foreach_start4 ?0 │┌──────┼► 85 foreach_step4 ?0 ││ ┌┼─ 90 jumpFalse4 {pc 310 (220)} ││ ││ 95 push1 @7 ││ ││ 97 push1 @8 ││ ││ 99 loadScalar1 %11 ││ ││ 101 push1 @9 ││ ││ 103 push1 @10 ││ ││ 105 invokeStk1 5 ││ ││ 107 nop ││ ┌┼┼─ 108 jumpFalse1 {pc 147 (39)} ││ │││ 110 loadScalar1 %6 ││ │││ 112 loadScalar1 %12 ││ │││ 114 loadScalar1 %4 ││ │││ 116 listLength ││ │││ 117 list 3 ││ │││ 122 lappendScalar1 %4 ││ │││ 124 pop ││ │││ 125 push1 @11 ││ │││ 127 loadScalar1 %5 ││ │││ 129 invokeStk1 2 ││ │││ 131 push1 @4 ││ │││ 133 dictSet 1 %5 ││ ┌┼┼┼─ 142 jump4 {pc 301 (159)} ││ │└┼┼► 147 push1 @7 ││ │ ││ 149 push1 @12 ││ │ ││ 151 loadScalar1 %11 ││ │ ││ 153 push1 @9 ││ │ ││ 155 push1 @13 ││ │ ││ 157 invokeStk1 5 ││ │ ││ 159 nop ││ │┌┼┼─ 160 jumpFalse4 {pc 299 (139)} ││ ││││ 165 loadScalar1 %2 ││ ││││ 167 push1 @14 ││ ││││ 169 dictGet 1 ││ ││││ 174 loadScalar1 %14 ││ ││││ 176 listIndex ││ ││││ 177 storeScalar1 %13 ││ ││││ 179 pop ││ ││││ 180 loadScalar1 %13 ││ ││││ 182 push1 @15 ││ ││││ 184 dictGet 1 ││ ││││ 189 push1 @16 ││ ││││ 191 streq ││ ┌┼┼┼┼─ 192 jumpFalse1 {pc 295 (103)} ││ │││││ 194 loadScalar1 %13 ││ │││││ 196 push1 @17 ││ │││││ 198 dictGet 1 ││ │││││ 203 beginCatch4 3 ││ │││││ 208 dictFirst %49 ││ ┌┼┼┼┼┼─ 213 jumpTrue4 {pc 282 (69)} ││┌┼┼┼┼┼┼► 218 storeScalar1 %15 │││││││││ 220 pop │││││││││ 221 storeScalar1 %16 │││││││││ 223 pop │││││││││ 224 loadScalar1 %6 │││││││││ 226 loadScalar1 %6 │││││││││ 228 loadScalar1 %16 │││││││││ 230 add │││││││││ 231 loadScalar1 %4 │││││││││ 233 listLength │││││││││ 234 list 3 │││││││││ 239 lappendScalar1 %4 │││││││││ 241 pop │││││││││ 242 push1 @11 │││││││││ 244 loadScalar1 %5 │││││││││ 246 invokeStk1 2 │││││││││ 248 push1 @4 │││││││││ 250 dictSet 1 %5 │││││││││ 259 pop │││││││││ 260 dictNext %49 ││└┼┼┼┼┼┼─ 265 jumpFalse4 {pc 218 (-47)} ││┌┼┼┼┼┼┼─ 270 jump1 {pc 282 (12)} │││││││││ 272 pushReturnOpts │││││││││ 273 pushResult │││││││││ 274 endCatch │││││││││ 275 unsetScalar 0 %49 │││││││││ 281 returnStk ││└┴┼┼┼┼┼► 282 pop ││ │││││ 283 pop ││ │││││ 284 endCatch ││ │││││ 285 unsetScalar 0 %49 ││ │││││ 291 push1 @4 ││ ┌┼┼┼┼┼─ 293 jump1 {pc 301 (8)} ││ │└┼┼┼┼► 295 push1 @4 ││ │┌┼┼┼┼─ 297 jump1 {pc 301 (4)} ││ │││└┼┼► 299 push1 @4 ││ └┴┴─┼┼► 301 pop │└─────┼┼─ 302 jump4 {pc 85 (-217)} │ ││ 307 nop │ ││ 308 nop │ ││ 309 nop │ └┼► 310 dictNext %46 └───────┼─ 315 jumpFalse4 {pc 60 (-255)} ┌┼─ 320 jump1 {pc 332 (12)} ││ 322 pushReturnOpts ││ 323 pushResult ││ 324 endCatch ││ 325 unsetScalar 0 %46 ││ 331 returnStk └┴► 332 pop 333 pop 334 endCatch 335 unsetScalar 0 %46 341 nop 342 nop 343 nop 344 loadScalar1 %6 346 strlen 347 storeScalar1 %18 349 pop 350 push1 @18 352 storeScalar1 %19 354 pop 355 push1 @19 357 storeScalar1 %20 359 pop ┌─ 360 jump4 {pc 606 (246)} ┌──────┼► 365 loadScalar1 %4 │ │ 367 loadScalar1 %20 │ │ 369 listIndex │ │ 370 dup │ │ 371 listIndexImm .0 │ │ 376 storeScalar1 %6 │ │ 378 pop │ │ 379 dup │ │ 380 listIndexImm .1 │ │ 385 storeScalar1 %12 │ │ 387 pop │ │ 388 dup │ │ 389 listIndexImm .2 │ │ 394 storeScalar1 %21 │ │ 396 pop │ │ 397 listRangeImm .3 .end │ │ 406 pop │ │ 407 loadScalar1 %21 │ │ 409 loadScalar1 %19 │ │ 411 le │ ┌┼─ 412 jumpFalse1 {pc 421 (9)} │ ┌┼┼─ 414 jump4 {pc 602 (188)} │ ┌┼┼┼─ 419 jump1 {pc 425 (6)} │ ││└┼► 421 loadScalar1 %21 │ ││ │ 423 storeScalar1 %19 │ └┼─┼► 425 pop │ │ │ 426 push1 @20 │ │ │ 428 loadScalar1 %6 │ │ │ 430 loadScalar1 %12 │ │ │ 432 invokeStk1 3 │ │ │ 434 tryCvtToNumeric │ │ │ 435 storeScalar1 %22 │ │ │ 437 pop │ │┌┼─ 438 jump4 {pc 587 (149)} │┌───┼┼┼► 443 loadScalar1 %4 ││ │││ 445 loadScalar1 %23 ││ │││ 447 listIndex ││ │││ 448 dup ││ │││ 449 listIndexImm .0 ││ │││ 454 storeScalar1 %24 ││ │││ 456 pop ││ │││ 457 dup ││ │││ 458 listIndexImm .1 ││ │││ 463 storeScalar1 %25 ││ │││ 465 pop ││ │││ 466 dup ││ │││ 467 listIndexImm .2 ││ │││ 472 storeScalar1 %26 ││ │││ 474 pop ││ │││ 475 listRangeImm .3 .end ││ │││ 484 pop ││ │││ 485 loadScalar1 %26 ││ │││ 487 loadScalar1 %21 ││ │││ 489 gt ││ ┌┼┼┼─ 490 jumpFalse1 {pc 509 (19)} ││ ││││ 492 loadScalar1 %22 ││ ││││ 494 push1 @21 ││ ││││ 496 loadScalar1 %24 ││ ││││ 498 loadScalar1 %25 ││ ││││ 500 invokeStk1 3 ││ ││││ 502 lt ││ ┌┼┼┼┼─ 503 jumpFalse1 {pc 509 (6)} ││ │││││ 505 push1 @1 ││┌┼┼┼┼┼─ 507 jump1 {pc 511 (4)} │││└┴┼┼┼► 509 push1 @19 ││└─┬┼┼┼► 511 jumpFalse1 {pc 584 (73)} ││ ││││ 513 loadScalar1 %23 ││ ││││ 515 push1 @22 ││ ││││ 517 loadScalar1 %21 ││ ││││ 519 loadScalar1 %4 ││ ││││ 521 lsetFlat 4 ││ ││││ 526 storeScalar1 %4 ││ ││││ 528 pop ││ ││││ 529 loadScalar1 %4 ││ ││││ 531 loadScalar1 %23 ││ ││││ 533 listIndex ││ ││││ 534 dup ││ ││││ 535 listIndexImm .0 ││ ││││ 540 storeScalar1 %6 ││ ││││ 542 pop ││ ││││ 543 dup ││ ││││ 544 listIndexImm .1 ││ ││││ 549 storeScalar1 %12 ││ ││││ 551 pop ││ ││││ 552 dup ││ ││││ 553 listIndexImm .2 ││ ││││ 558 storeScalar1 %21 ││ ││││ 560 pop ││ ││││ 561 listRangeImm .3 .end ││ ││││ 570 pop ││ ││││ 571 push1 @20 ││ ││││ 573 loadScalar1 %6 ││ ││││ 575 loadScalar1 %12 ││ ││││ 577 invokeStk1 3 ││ ││││ 579 tryCvtToNumeric ││ ││││ 580 storeScalar1 %22 ││ ┌┼┼┼┼─ 582 jump1 {pc 586 (4)} ││ │└┼┼┼► 584 push1 @4 ││ └─┼┼┼► 586 pop ││ │└┼► 587 incrScalar1Imm %23 1 ││ │ │ 590 loadScalar1 %4 ││ │ │ 592 listLength ││ │ │ 593 lt │└───┼─┼─ 594 jumpTrue4 {pc 443 (-151)} │ │ │ 599 nop │ │ │ 600 nop │ │ │ 601 nop │ └─┼► 602 incrScalar1Imm %20 1 │ │ 605 pop │ └► 606 loadScalar1 %20 │ 608 storeScalar1 %23 │ 610 loadScalar1 %4 │ 612 listLength │ 613 lt └──────── 614 jumpTrue4 {pc 365 (-249)} 619 nop 620 nop 621 nop 622 push1 @23 624 push1 @24 626 push1 @25 628 loadScalar1 %4 630 storeScalar1 %51 632 pop 633 push1 @4 635 storeScalar1 %50 637 pop 638 foreach_start4 ?1 ┌─► 643 foreach_step4 ?1 │┌─ 648 jumpFalse1 {pc 662 (14)} ││ 650 loadScalar1 %23 ││ 652 listIndexImm .2 ││ 657 lappendScalar1 %50 ││ 659 pop └┼─ 660 jump1 {pc 643 (-17)} └► 662 loadScalar1 %50 664 unsetScalar 0 %50 670 invokeStk1 4 672 storeScalar1 %27 674 pop 675 loadScalar1 %4 677 listLength 678 storeScalar1 %20 680 pop ┌─ 681 jump1 {pc 792 (111)} ┌─────┼► 683 loadScalar1 %20 │ │ 685 loadScalar1 %27 │ │ 687 listIn │ ┌┼─ 688 jumpFalse1 {pc 697 (9)} │ ┌┼┼─ 690 jump4 {pc 792 (102)} │ ┌┼┼┼─ 695 jump1 {pc 699 (4)} │ ││└┼► 697 push1 @4 │ └┼─┼► 699 pop │ │ │ 700 push1 @19 │ │ │ 702 storeScalar1 %23 │ │ │ 704 pop │ │┌┼─ 705 jump1 {pc 759 (54)} │┌──┼┼┼► 707 loadScalar1 %4 ││ │││ 709 loadScalar1 %23 ││ │││ 711 push1 @22 ││ │││ 713 lindexMulti 3 ││ │││ 718 loadScalar1 %20 ││ │││ 720 gt ││ ┌┼┼┼─ 721 jumpFalse1 {pc 752 (31)} ││ ││││ 723 loadScalar1 %23 ││ ││││ 725 push1 @22 ││ ││││ 727 loadScalar1 %4 ││ ││││ 729 loadScalar1 %23 ││ ││││ 731 push1 @22 ││ ││││ 733 lindexMulti 3 ││ ││││ 738 push1 @1 ││ ││││ 740 sub ││ ││││ 741 loadScalar1 %4 ││ ││││ 743 lsetFlat 4 ││ ││││ 748 storeScalar1 %4 ││┌┼┼┼┼─ 750 jump1 {pc 754 (4)} │││└┼┼┼► 752 push1 @4 ││└─┼┼┼► 754 pop ││ │││ 755 incrScalar1Imm %23 1 ││ │││ 758 pop ││ │└┼► 759 loadScalar1 %23 ││ │ │ 761 loadScalar1 %4 ││ │ │ 763 listLength ││ │ │ 764 lt │└──┼─┼─ 765 jumpTrue1 {pc 707 (-58)} │ │ │ 767 nop │ │ │ 768 nop │ │ │ 769 nop │ │ │ 770 push1 @11 │ │ │ 772 loadScalar1 %5 │ │ │ 774 invokeStk1 2 │ │ │ 776 push1 @1 │ │ │ 778 sub │ │ │ 779 dictUnset 1 %5 │ │ │ 788 pop │ │ │ 789 nop │ │ │ 790 nop │ │ │ 791 nop │ └─┴► 792 incrScalar1Imm %20 -1 │ 795 push1 @19 │ 797 ge └─────── 798 jumpTrue1 {pc 683 (-115)} 800 nop 801 nop 802 nop 803 loadScalar1 %2 805 push1 @6 807 dictGet 1 812 beginCatch4 13 817 dictFirst %53 ┌─ 822 jumpTrue4 {pc 1294 (472)} ┌────────┼► 827 storeScalar1 %31 │ │ 829 pop │ │ 830 storeScalar1 %7 │ │ 832 pop │ │ 833 loadScalar1 %5 │ │ 835 dup │ │ 836 listLength │ │ 837 push1 @1 │ │ 839 bitand │ ┌┼─ 840 jumpFalse1 {pc 855 (15)} │ ││ 842 push1 @26 │ ││ 844 push1 @27 │ ││ 846 returnImm 1 0 │ └┼► 855 storeScalar1 %54 │ │ 857 pop │ │ 858 arrayExistsImm 33 │ ┌┼─ 863 jumpTrue1 {pc 870 (7)} │ ││ 865 arrayMakeImm 33 │ └┼► 870 foreach_start4 ?2 │ ┌─┼► 875 foreach_step4 ?2 │ │┌┼─ 880 jumpFalse1 {pc 891 (11)} │ │││ 882 loadScalar1 %56 │ │││ 884 loadScalar1 %57 │ │││ 886 storeArray1 %33 │ │││ 888 pop │ └┼┼─ 889 jump1 {pc 875 (-14)} │ └┼► 891 unsetScalar 0 %54 │ │ 897 nop │ │ 898 nop │ │ 899 nop │ │ 900 push1 @11 │ │ 902 loadScalar1 %5 │ │ 904 invokeStk1 2 │ │ 906 storeScalar1 %38 │ │ 908 pop │ │ 909 loadScalar1 %4 │ │ 911 storeScalar1 %58 │ │ 913 pop │ │ 914 foreach_start4 ?3 │┌───────┼► 919 foreach_step4 ?3 ││ ┌┼─ 924 jumpFalse4 {pc 1193 (269)} ││ ││ 929 loadScalar1 %41 ││ ││ 931 dup ││ ││ 932 listIndexImm .0 ││ ││ 937 storeScalar1 %6 ││ ││ 939 pop ││ ││ 940 dup ││ ││ 941 listIndexImm .1 ││ ││ 946 storeScalar1 %12 ││ ││ 948 pop ││ ││ 949 dup ││ ││ 950 listIndexImm .2 ││ ││ 955 storeScalar1 %20 ││ ││ 957 pop ││ ││ 958 listRangeImm .3 .end ││ ││ 967 pop ││ ││ 968 loadScalar1 %38 ││ ││ 970 loadScalar1 %20 ││ ││ 972 sub ││ ││ 973 push1 @22 ││ ││ 975 sub ││ ││ 976 storeScalar1 %20 ││ ││ 978 pop ││ ││ 979 loadScalar1 %6 ││ ││ 981 loadScalar1 %31 ││ ││ 983 eq ││ ┌┼┼─ 984 jumpFalse1 {pc 1043 (59)} ││ │││ 986 push1 @28 ││ │││ 988 push1 @29 ││ │││ 990 loadScalar1 %20 ││ │││ 992 push1 @30 ││ │││ 994 concat1 3 ││ │││ 996 push1 @31 ││ │││ 998 loadScalar1 %6 ││ │││ 1000 loadScalar1 %12 ││ │││ 1002 lt ││ │││ 1003 listIndex ││ │││ 1004 push1 @32 ││ │││ 1006 invokeStk1 4 ││ │││ 1008 pop ││ ┌┼┼┼─ 1009 jump1 {pc 1028 (19)} ││ ┌┼┼┼┼► 1011 push1 @28 ││ │││││ 1013 push1 @29 ││ │││││ 1015 loadScalar1 %20 ││ │││││ 1017 push1 @30 ││ │││││ 1019 concat1 3 ││ │││││ 1021 push1 @33 ││ │││││ 1023 push1 @32 ││ │││││ 1025 invokeStk1 4 ││ │││││ 1027 pop ││ │└┼┼┼► 1028 incrScalar1Imm %20 1 ││ │ │││ 1031 loadScalar1 %38 ││ │ │││ 1033 lt ││ └─┼┼┼─ 1034 jumpTrue1 {pc 1011 (-23)} ││ │││ 1036 push1 @4 ││ ┌┼┼┼─ 1038 jump4 {pc 1184 (146)} ││ │└┼┼► 1043 loadScalar1 %12 ││ │ ││ 1045 loadScalar1 %31 ││ │ ││ 1047 eq ││ │┌┼┼─ 1048 jumpFalse1 {pc 1112 (64)} ││ ││││ 1050 push1 @28 ││ ││││ 1052 push1 @29 ││ ││││ 1054 loadScalar1 %20 ││ ││││ 1056 push1 @30 ││ ││││ 1058 concat1 3 ││ ││││ 1060 push1 @31 ││ ││││ 1062 loadScalar1 %6 ││ ││││ 1064 loadScalar1 %12 ││ ││││ 1066 gt ││ ││││ 1067 listIndex ││ ││││ 1068 push1 @32 ││ ││││ 1070 invokeStk1 4 ││ ││││ 1072 pop ││ ┌┼┼┼┼─ 1073 jump1 {pc 1092 (19)} ││ ┌┼┼┼┼┼► 1075 push1 @28 ││ ││││││ 1077 push1 @29 ││ ││││││ 1079 loadScalar1 %20 ││ ││││││ 1081 push1 @30 ││ ││││││ 1083 concat1 3 ││ ││││││ 1085 push1 @33 ││ ││││││ 1087 push1 @32 ││ ││││││ 1089 invokeStk1 4 ││ ││││││ 1091 pop ││ │└┼┼┼┼► 1092 incrScalar1Imm %20 1 ││ │ ││││ 1095 loadScalar1 %38 ││ │ ││││ 1097 lt ││ └─┼┼┼┼─ 1098 jumpTrue1 {pc 1075 (-23)} ││ ││││ 1100 nop ││ ││││ 1101 nop ││ ││││ 1102 nop ││ ││││ 1103 incrScalar1Imm %20 -1 ││ ││││ 1106 push1 @34 ││ ││││ 1108 lappendArray1 %33 ││ ┌┼┼┼┼─ 1110 jump1 {pc 1184 (74)} ││ ││└┼┼► 1112 loadScalar1 %6 ││ ││ ││ 1114 loadScalar1 %31 ││ ││ ││ 1116 lt ││ ││┌┼┼─ 1117 jumpFalse1 {pc 1130 (13)} ││ │││││ 1119 loadScalar1 %12 ││ │││││ 1121 loadScalar1 %31 ││ │││││ 1123 gt ││ ┌┼┼┼┼┼─ 1124 jumpFalse1 {pc 1130 (6)} ││ ││││││ 1126 push1 @1 ││ ┌┼┼┼┼┼┼─ 1128 jump1 {pc 1132 (4)} ││ │└┼┼┴┼┼► 1130 push1 @19 ││ └─┼┼┬┼┼► 1132 jumpTrue1 {pc 1160 (28)} ││ │││││ 1134 loadScalar1 %6 ││ │││││ 1136 loadScalar1 %31 ││ │││││ 1138 gt ││ ┌┼┼┼┼┼─ 1139 jumpFalse1 {pc 1152 (13)} ││ ││││││ 1141 loadScalar1 %12 ││ ││││││ 1143 loadScalar1 %31 ││ ││││││ 1145 lt ││ ┌┼┼┼┼┼┼─ 1146 jumpFalse1 {pc 1152 (6)} ││ │││││││ 1148 push1 @1 ││┌┼┼┼┼┼┼┼─ 1150 jump1 {pc 1154 (4)} │││└┴┼┼┼┼┼► 1152 push1 @19 ││└─┬┼┼┼┼┼► 1154 jumpTrue1 {pc 1160 (6)} ││ ││││││ 1156 push1 @19 ││ ┌┼┼┼┼┼┼─ 1158 jump1 {pc 1162 (4)} ││ │└┼┼┴┼┼► 1160 push1 @1 ││ └─┼┼┬┼┼► 1162 jumpFalse1 {pc 1182 (20)} ││ │││││ 1164 push1 @28 ││ │││││ 1166 push1 @29 ││ │││││ 1168 loadScalar1 %20 ││ │││││ 1170 push1 @30 ││ │││││ 1172 concat1 3 ││ │││││ 1174 push1 @35 ││ │││││ 1176 push1 @36 ││ │││││ 1178 invokeStk1 4 ││ ┌┼┼┼┼┼─ 1180 jump1 {pc 1184 (4)} ││ │││└┼┼► 1182 push1 @4 ││ └┴┴─┼┼► 1184 pop │└──────┼┼─ 1185 jump4 {pc 919 (-266)} │ ││ 1190 nop │ ││ 1191 nop │ ││ 1192 nop │ └┼► 1193 push1 @37 │ │ 1195 push1 @38 │ │ 1197 push1 @39 │ │ 1199 push1 @40 │ │ 1201 push1 @41 │ │ 1203 loadScalar1 %5 │ │ 1205 invokeStk1 2 │ │ 1207 storeScalar1 %61 │ │ 1209 pop │ │ 1210 push1 @4 │ │ 1212 storeScalar1 %60 │ │ 1214 pop │ │ 1215 foreach_start4 ?4 │ ┌─┼► 1220 foreach_step4 ?4 │ │┌┼─ 1225 jumpFalse1 {pc 1249 (24)} │ │││ 1227 loadScalar1 %3 │ │││ 1229 push1 @23 │ │││ 1231 push1 @25 │ │││ 1233 loadScalar1 %45 │ │││ 1235 loadArray1 %33 │ │││ 123-7 invokeStk1 3 │ │││ 1239 dictGet 1 │ │││ 1244 lappendScalar1 %60 │ │││ 1246 pop │ └┼┼─ 1247 jump1 {pc 1220 (-27)} │ └┼► 1249 loadScalar1 %60 │ │ 1251 unsetScalar 0 %60 │ │ 1257 push1 @4 │ │ 1259 invokeStk1 3 │ │ 1261 loadScalar1 %18 │ │ 1263 loadScalar1 %31 │ │ 1265 loadScalar1 %7 │ │ 1267 invokeStk1 6 │ │ 1269 invokeStk1 2 │ │ 1271 pop │ │ 1272 dictNext %53 └────────┼─ 1277 jumpFalse4 {pc 827 (-450)} ┌┼─ 1282 jump1 {pc 1294 (12)} ││ 1284 pushReturnOpts ││ 1285 pushResult ││ 1286 endCatch ││ 1287 unsetScalar 0 %53 ││ 1293 returnStk └┴► 1294 pop 1295 pop 1296 endCatch 1297 unsetScalar 0 %53 1303 push1 @4 1305 done ====== <> [RS] 2013-12-03 - Could the following be a bug? (Note the space between unsetScalar and 1): ====== suchenwi@suchenwi-NC10:~$ tclkit % proc f {} {set x 1; unset x} % tcl::unsupported::disassemble proc f ByteCode 0x0x93fc5b8, refCt 1, epoch 15, interp 0x0x936c7a0 (epoch 15) Source "set x 1; unset x" Cmds 2, src 16, inst 14, litObjs 2, aux 0, stkDepth 1, code/src 0.00 Proc 0x0x9401ec0, refCt 1, args 0, compiled locals 1 slot 0, scalar, "x" Commands 2: 1: pc 0-4, src 0-6 2: pc 5-12, src 9-15 Command 1: "set x 1" (0) push1 0 # "1" (2) storeScalar1 %v0 # var "x" (4) pop Command 2: "unset x" (5) unsetScalar 1 %v0 # var "x" <---------------------- here (11) push1 1 # "" (13) done % info pa 8.6.1 ====== ---- [AMG]: What's going on with PC 47 until 61? What are those jumps and pops for? ======none proc ftw_9 {{dirs .}} { while {[llength $dirs]} { set dirs [concat [lassign $dirs name] [glob -nocomplain -directory $name -type d *]] } } tcl::unsupported::disassemble proc ftw_9 ByteCode 0x0x9b81f0, refCt 1, epoch 15, interp 0x0x94dac0 (epoch 15) Source "\n while {[llength $dirs]} {\n set dirs [conc"... Cmds 6, src 130, inst 86, litObjs 7, aux 0, stkDepth 8, code/src 0.00 Proc 0x0xa0e060, refCt 1, args 1, compiled locals 2 slot 0, scalar, arg, "dirs" slot 1, scalar, "name" Exception ranges 2, depth 2: 0: level 0, loop, pc 2-67, continue 69, break 83 1: level 1, loop, pc 45-46, continue 55, break 49 Commands 6: 1: pc 0-84, src 5-128 2: pc 2-67, src 39-122 3: pc 11-65, src 49-121 4: pc 11-30, src 57-74 5: pc 31-60, src 78-120 6: pc 69-80, src 13-25 Command 1: "while {[llength $dirs]} {\n set dirs [concat [la"... (0) jump1 +69 # pc 69 Command 2: "set dirs [concat [lassign $dirs name] [glob -nocomplain"... (2) startCommand +66 3 # next cmd at pc 68, 3 cmds start here Command 3: "concat [lassign $dirs name] [glob -nocomplain -director"... Command 4: "lassign $dirs name"... (11) loadScalar1 %v0 # var "dirs" (13) dup (14) listIndexImm 0 (19) storeScalar1 %v1 # var "name" (21) pop (22) listRangeImm 1 end Command 5: "glob -nocomplain -directory $name -type d *"... (31) push1 0 # "glob" (33) push1 1 # "-nocomplain" (35) push1 2 # "-directory" (37) loadScalar1 %v1 # var "name" (39) push1 3 # "-type" (41) push1 4 # "d" (43) push1 5 # "*" (45) invokeStk1 7 (47) jump1 +14 # pc 61 (49) pop (50) jump4 +33 # pc 83 (55) pop (56) jump4 +13 # pc 69 (61) concatStk 2 (66) storeScalar1 %v0 # var "dirs" (68) pop Command 6: "llength $dirs"... (69) startCommand +12 1 # next cmd at pc 81 (78) loadScalar1 %v0 # var "dirs" (80) listLength (81) jumpTrue1 -79 # pc 2 (83) push1 6 # "" (85) done ====== [DKF]: Those are exception handlers that convert exceptions thrown from the `invokeStk1` (remember, it doesn't know that it ''won't'') into jumps to the correct way to handle the [break] (start at `(49)`) or the [continue] (start at `(55)`). This is defined by exception range #1. <> Command | Internals