bytecode

Tcl bytecode is the instruction set targeted by TAL

Documentation

$tcl_traceExec

Reading

Wikipedia

See Also

Parsing, Bytecodes and Execution
Playing bytecode
Brute force meets Goedel
Proc to bytecodes: when, how does it happen
Commands affecting Bytecoding
The anatomy of a bytecoded command
Why compile to bytecode
bytecode dissasembly and/or examination
script compilation

Description

DKF 2003-01-06 (from .NET):

... the current Tcl bytecodes are defined at a level that is meaningful to Tcl, not at a level that virtually any other bytecode operates at; very few bytecodes have an opcode for "increment-hash-entry-and-fire-attached-traces"! Given that, you're either just producing another language reimplementation (like Jacl) or you're taking on the hard task of defining how to go from Tcl to the fairly-common low-level register-based bytecode engines that so many other languages use. Which would be nice and useful, but is a really huge (and definitely complex and deep) task...

Why Byte-Coded Commands Can Be Faster Than C-Coded Commands

Byte-Coded commands are sometimes faster than commands implemented in an external language like C. MS, Tcl Chatroom, 2013-12-31, offered these reasons:

  1. Byte-coded commands access local variables directly, whereas commands implemented in C have to resolve them at runtime.
  2. Dispatch to an external command is slower than dispatch to a byte-coded command
  3. Often, only the most frequently-used code-paths of a command are byte-coded, and corner cases fall back to the C implementation of the command.

Empty Procedure

When a procedure is defined with exactly args as the only item in its argument specification and no commands in its body, calls to it are elided in the bytecode of other procedures

proc one args {
}

proc two {} {
        one
}

# trigger compilation
two

puts [::tcl::unsupported::disassemble proc two]

output:

ByteCode 0x0x55cfa663ae10, refCt 1, epoch 17, interp 0x0x55cfa660e980 (epoch 17)
  Source "\n\ton..."
  File "/path/to/script" Line 68
  Cmds 1, src 6, inst 3, litObjs 1, aux 0, stkDepth 1, code/src 0.00
  Proc 0x0x55cfa665d7d0, refCt 1, args 0, compiled locals 0
  Commands 1:
      1: pc 0-1, src 2-4
  Command 1: "one..."
    (0) push1 0         # ""
    (2) done 

However, the elision is not transitive:

proc zero args {}


proc one args {
        zero
}

proc two {} {
        one
}

# trigger compilation
two

puts [::tcl::unsupported::disassemble proc two]

output:

ByteCode 0x0x55eb428e6e10, refCt 1, epoch 17, interp 0x0x55eb428ba980 (epoch 17)
  Source "\n\ton..."
  File "/path/to/script" Line 68
  Cmds 1, src 6, inst 3, litObjs 1, aux 0, stkDepth 1, code/src 0.00
  Proc 0x0x55eb429097d0, refCt 1, args 0, compiled locals 0
  Commands 1:
      1: pc 0-1, src 2-4
  Command 1: "one..."
    (0) push1 0         # ""
    (2) done