tbcx - serialize, load, and inspect precompiled Tcl 9.1 bytecode (procs, OO methods, and lambdas)
tbcx::save in out
tbcx::load in
tbcx::dump filename
The tbcx extension provides three subcommands that enable an efficient save → load → eval pipeline for Tcl 9.1 scripts.
The goal is to pay the cost of parsing/compiling at save time so that loading is as fast as reading a compact binary, while remaining functionally equivalent to source of the original script.
Artifacts store the compiled top-level, precompiled proc bodies, TclOO method/ctor/dtor bodies, and lambda literals for use with apply. Loading installs these into the current interpreter and executes the top-level block in the caller's current namespace.
Synopsis
Compile a script and write a .tbcx artifact.
Parameters
in One of:
out One of:
Behavior
Returns
The output object: either the normalized path written, or the writable channel handle.
Errors
Typical errors include: unreadable input; unwritable output; version/format mismatch; unknown/unsupported AuxData; size limit exceeded (code, literals, AuxData, exception ranges, strings); short read/write.
The interpreter result contains a descriptive message.
Notes
Examples
# Save from path \-> path
set path [tbcx::save ./app.tcl ./app.tbcx]
# Save from string value \-> path
set script {proc hi {} {puts Hello}; hi}
tbcx::save $script ./hello.tbcx
# Save from channel \-> channel
set in [open ./lib/foo.tcl r]
set out [open ./foo.tbcx w]
fconfigure $in -translation binary -eofchar {}
fconfigure $out -translation binary -eofchar {}
try {
tbcx::save $in $out
} finally {
close $in
close $out
}
Synopsis
Load a .tbcx artifact, install precompiled entities, and execute the top-level block.
Parameters
in One of:
Behavior
Returns
Empty string on success.
Errors
Typical errors include: unreadable input; bad header; incompatible Tcl version; malformed/unknown section; size limit exceeded; short read; class or namespace creation errors during top-level evaluation.
Notes
Examples
# Load into current namespace
tbcx::load ./app.tbcx
# Load into a dedicated namespace
namespace eval ::app { tbcx::load ./app.tbcx }
# Load from an open channel
set ch [open ./app.tbcx r]
fconfigure $ch -translation binary -eofchar {}
try {
tbcx::load $ch
} finally {
close $ch
}
Synopsis
Disassemble and describe a .tbcx artifact in human-readable form.
Parameters
filename A readable path to a .tbcx file.
Behavior
Reads the artifact and prints: header fields; section summaries; literals and AuxData; exception ranges;
and a disassembly of the top-level, proc, method, and lambda bodies.
Returns
A string containing the formatted dump.
Errors
Unreadable file; bad header; malformed section; short read.
Examples
% package require tbcx
% tbcx::save {set a 1} out
% tbcx::dump out
TBCX Header:
magic = 0x58434254 ('T''B''C''X')
format = 9
tcl_version = 9.1.0 (type 0)
top: code=12, except=0, lits=2, aux=0, locals=1, stack=2
Top-level block:
Disassembly (top-level):
ByteCode 0x7f9963089e10, refCt 1, epoch 20, interp 0x7f9963816a10 (epoch 20)
Source ""
Cmds 0, src 0, inst 11, litObjs 1, aux 0, stkDepth 1, code/src 0.00
(0) push 0 # "1"
(5) storeScalar %v0
(10) done
code=11, stack=1, lits=1, aux=0, except=0
Locals (1):
[0] "a"
Literals:
[0] (bignum) 1
Procs: 0
Classes: 0
Methods: 0
This section summarizes the on-disk structure.
Header Magic + format version + producing Tcl version; size/count metadata for the top-level block (code length, literal count, AuxData count, exception ranges, locals, max stack).
Sections (order) (1) Top-level block (code, literals, AuxData, exceptions, locals epilogue); (2) Procs (FQN, ns, arg spec, compiled block); (3) Classes (advisory catalog; actual creation occurs at load time); (4) Methods (class, kind, name, args, compiled block).
Literal kinds boolean, (wide)int/uint, double, bignum, string, bytearray, list, dict, embedded bytecode, and lambda-bytecode literals for use with apply.
AuxData families jump tables (string or numeric), dictupdate, foreach (legacy/new).
Literals in the script that represent lambdas for apply (lists of the form {args body ns?}) are compiled and serialized as lambda-bytecode literals at save time.
On load, both the compiled body and the optional namespace element are rehydrated so that the first call to apply does not trigger compilation.
Artifacts are portable across little- and big-endian hosts. The loader detects host byte order once and applies a tight in-place swap over bulk sections that require conversion, avoiding per-field branching so cross-endian loads remain close to native performance.
Loading executes the precompiled top-level, then installs precompiled proc/method bodies and rehydrates lambda literals. The intent is to be functionally indistinguishable from source of the original script, with the benefit of faster startup due to avoided parsing/compilation.
Sanity caps exist for code size, literal count (including lambdas), AuxData count, exception ranges, and string lengths. Exceeding limits produces an error.
Representative messages include: "bad header", "incompatible Tcl version", "short read/write", "unsupported AuxData kind", "input is neither an open channel nor a readable file", and "errors while evaluating top-level".
Loading executes code. Only load artifacts you trust.
source(n), TclOO(n)
© 2025 Miguel Banon
MIT License.
↑ Top