Standard Tcl Bytecodes
General Operations
These operations are just used to do general things to the stack, manage the control flow, etc.
done
Finish ByteCode execution and return
stktop
(top stack item)Stack:
... value =>
TERMINATE
push1 LIT1
Push object at ByteCode
objArray[op1]
Stack:
... => ... value
push4 LIT4
Push object at ByteCode
objArray[op4]
Stack:
... => ... value
nop
Do nothing
Stack:
... => ...
pop
Pop the topmost stack object
Stack:
... value => ...
dup
Duplicate the topmost stack object and push the result
Stack:
... value => ... value value
over UINT4
Duplicate the arg-th element from top of stack (TOS=0)
Stack:
... valN valN-1 valN-2 ... val1 val0 => ... valN valN-1 valN-2 ... val1 val0 valN
reverse UINT4
Reverse the order of the arg elements at the top of stack
Stack:
... valN valN-1 ... val1 => ... val1 ... valN-1 valN
break
Abort closest enclosing loop; if none, return
TCL_BREAK
code.
continue
Skip to next iteration of closest enclosing loop; if none, return
TCL_CONTINUE
code.
beginCatch4 UINT4
Record start of catch with the operand's exception index. Push the current stack depth onto a special catch stack.
endCatch
End of last catch. Pop the bytecode interpreter's catch stack. Must have the same stack depth as the beginCatch4 that it matches.
pushResult
Push the interpreter's object result onto the stack.
Stack:
... => ... result
pushReturnCode
Push interpreter's return code (e.g.
TCL_OK
orTCL_ERROR
) as a new object onto the stack.Stack:
... => ... code
pushReturnOpts
Push the interpreter's return option dictionary as an object on the stack.
Stack:
... => ... optDict
returnStk
Compiled
return
; options and result are on the stack, code and level are in the options.
returnImm INT4 UINT4
Compiled
return
, code, level are operands; options and result are on the stack.
syntax INT4 UINT4
Compiled bytecodes to signal syntax error. Equivalent to returnImm except for the
ERR_ALREADY_LOGGED
flag in the interpreter.
jump1 OFFSET1
Jump relative to (pc + op1)
jump4 OFFSET4
Jump relative to (pc + op4)
jumpTrue1 OFFSET1
Jump relative to (pc + op1) if stktop expr object is true
jumpTrue4 OFFSET4
Jump relative to (pc + op4) if stktop expr object is true
jumpFalse1 OFFSET1
Jump relative to (pc + op1) if stktop expr object is false
jumpFalse4 OFFSET4
Jump relative to (pc + op4) if stktop expr object is false
startCommand OFFSET4 UINT4
Start of bytecoded command: op is the length of the cmd's code, op2 is number of commands here
jumpTable AUX4
Jump according to the jump-table (in AuxData as indicated by the operand) and the argument popped from the list. Always executes the next instruction if no match against the table's entries was found.
Stack:
... value => ...
Note that the jump table contains offsets relative to the PC when it points to this instruction; the code is relocatable.
returnCodeBranch
Jump to next instruction based on the return code on top of stack
ERROR: +1; RETURN: +3; BREAK: +5; CONTINUE: +7;
Other non-OK: +9
yield
Makes the current coroutine yield the value at the top of the stack, and places the response back on top of the stack when it resumes.
Stack:
... valueToYield => ... resumeValue
tailcall UINT1
Do a tailcall with the opnd items on the stack as the thing to tailcall to; opnd must be greater than 0 for the semantics to work right.
yieldToInvoke
Makes the current coroutine yield the value at the top of the stack, invoking the given command/args with resolution in the given namespace (all packed into a list), and places the list of values that are the response back on top of the stack when it resumes.
Stack:
... [list ns cmd arg1 ... argN] => ... resumeList
String Operations
These are operations that manipulate a string. They always operate on a string value, and usually give a result of the transformed string; where the value is of refcount 1 (i.e., it must only be on the stack) then the transformation is performed in-place where that is meaningful. Comparison and matching operations don't follow that rule, of course.
strcat UINT1
Concatenate the top op1 items and push result
streq
Str Equal:
push (stknext eq stktop)
strneq
Str !Equal:
push (stknext neq stktop)
strcmp
Str Compare:
push (stknext cmp stktop)
strlen
Str Length:
push (strlen stktop)
strindex
Str Index:
push (strindex stknext stktop)
strmatch INT1
Str Match:
push (strmatch stknext stktop) opnd == nocase
strmap
Simplified version of
string map
that only applies one change string, and only case-sensitively.Stack:
... from to string => ... changedString
strfind
Find the first index of a needle string in a haystack string, producing the index (integer) or -1 if nothing found.
Stack:
... needle haystack => ... index
strrfind
Find the last index of a needle string in a haystack string, producing the index (integer) or -1 if nothing found.
Stack:
... needle haystack => ... index
strrangeImm IDX4 IDX4
String Range:
push (string range stktop op4 op4)
strrange
String Range with non-constant arguments.
Stack:
... string idxA idxB => ... substring
strtrim
string trim
core: removes the characters (designated by the value at the top of the stack) from both ends of the string and pushes the resulting string.Stack:
... string charset => ... trimmedString
strtrimLeft
string trimleft
core: removes the characters (designated by the value at the top of the stack) from the left of the string and pushes the resulting string.Stack:
... string charset => ... trimmedString
strtrimRight
string trimright
core: removes the characters (designated by the value at the top of the stack) from the right of the string and pushes the resulting string.Stack:
... string charset => ... trimmedString
strcaseUpper
string toupper
core: converts whole string to upper case using the default (extended "C" locale) rules.Stack:
... string => ... newString
strcaseLower
string tolower
core: converts whole string to upper case using the default (extended "C" locale) rules.Stack:
... string => ... newString
strcaseTitle
string totitle
core: converts whole string to upper case using the default (extended "C" locale) rules.Stack:
... string => ... newString
strreplace
string replace
core: replaces a non-empty range of one string with the contents of another.Stack:
... string fromIdx toIdx replacement => ... newString
strclass SCLS1
See if all the characters of the given string are a member of the specified (by opnd) character class. Note that an empty string will satisfy the class check (standard definition of "all"). Stack:
... stringValue => ... boolean
regexp INT1
Regexp:
push (regexp stknext stktop) opnd == nocase
Invoke/Eval Operations
These operations are expected to be reentering the bytecode engine; it is a common occurrence with them.
evalStk
Evaluate command in stktop using
Tcl_EvalObj
.
exprStk
Execute expression in stktop using
Tcl_ExprStringObj
.
invokeStk1 UINT1
Invoke command named
objv[0]; <objc,objv> = <op1,top op1>
invokeStk4 UINT4
Invoke command named
objv[0]; <objc,objv> = <op4,top op4>
invokeReplace UINT4 UINT1
Invoke command named
objv[0]
, replacing the first two words with the word at the top of the stack;
<objc,objv> = <op4,top op4 after popping 1>
callBuiltinFunc1 UINT1
Call builtin math function with index op1; any args are on stk. OBSOLETE!
callFunc1 UINT1
Call non-builtin func
objv[0]; <objc,objv>=<op1,top op1>
OBSOLETE!
Expansion Operations
Operations used to handle Tcl's {*}
syntax in cases where it can't be compiled into something more efficient.
NOTE: the stack effects of expandStkTop and invokeExpanded are wrong - but it cannot be done right at compile time, the stack effect is only known at run time. The value for invokeExpanded is estimated better at compile time.
See the comments in
tclCompile.c
, where invokeExpanded is emitted.
expandStart
Start of command with
{*}
(expanded) arguments
expandStkTop UINT4
Expand the list at stacktop: push its elements on the stack
invokeExpanded
Invoke the command marked by the last expandStart
expandDrop
Drops an element from the auxiliary stack, popping stack elements until the matching stack depth is reached.
Variable Read and Write Operations
Access to Tcl's variables. Variables may be either located in the Local Variable Table (LVT) in which case they can be referred to by index, or they can be in a hash table associated with a namespace. Local variables can also be looked up by name; this is a slow process.
loadScalar1 LVT1
Load scalar variable at index op1 <= 255 in call frame
loadScalar4 LVT4
Load scalar variable at index op1 >= 256 in call frame
loadScalarStk
Load scalar variable; scalar's name is stktop. NEVER ISSUED.
loadArray1 LVT1
Load array element; array at slot op1<=255, element is stktop
loadArray4 LVT4
Load array element; array at slot op1 > 255, element is stktop
loadArrayStk
Load array element; element is stktop, array name is stknext
loadStk
Load general variable; unparsed variable name is stktop
storeScalar1 LVT1
Store scalar variable at op1<=255 in frame; value is stktop
storeScalar4 LVT4
Store scalar variable at op1 > 255 in frame; value is stktop
storeScalarStk
Store scalar; value is stktop, scalar name is stknext. NEVER ISSUED.
storeArray1 LVT1
Store array element; array at op1<=255, value is top then elem
storeArray4 LVT4
Store array element; array at op1>=256, value is top then elem
storeArrayStk
Store array element; value is stktop, then elem, array names
storeStk
Store general variable; value is stktop, then unparsed name
existScalar LVT4
Test if scalar variable at index op1 in call frame exists
existArray LVT4
Test if array element exists; array at slot op1, element is stktop
existArrayStk
Test if array element exists; element is stktop, array name is stknext
existStk
Test if general variable exists; unparsed variable name is stktop
unsetScalar UINT1 LVT4
Make scalar variable at index op2 in call frame cease to exist; op1 is 1 for errors on problems, 0 otherwise
unsetArray UINT1 LVT4
Make array element cease to exist; array at slot op2, element is stktop; op1 is 1 for errors on problems, 0 otherwise
unsetArrayStk UINT1
Make array element cease to exist; element is stktop, array name is stknext; op1 is 1 for errors on problems, 0 otherwise
unsetStk UINT1
Make general variable cease to exist; unparsed variable name is stktop; op1 is 1 for errors on problems, 0 otherwise
upvar LVT4
finds level and otherName in stack, links to local variable at index op1. Leaves the level on stack.
nsupvar LVT4
finds namespace and otherName in stack, links to local variable at index op1. Leaves the namespace on stack.
variable LVT4
finds namespace and otherName in stack, links to local variable at index op1. Leaves the namespace on stack.
Special Variable Modification Operations
These form the core of the incr
and append
commands. (There's also lappend
, which is listed below under List operations.)
incrScalar1 LVT1
Incr scalar at index op1<=255 in frame; incr amount is stktop
incrScalarStk
Incr scalar; incr amount is stktop, scalar's name is stknext. NEVER ISSUED.
incrArray1 LVT1
Incr array elem; arr at slot op1<=255, amount is top then elem
incrArrayStk
Incr array element; amount is top then elem then array names
incrStk
Incr general variable; amount is stktop then unparsed var name
incrScalar1Imm LVT1 INT1
Incr scalar at slot op1 <= 255; amount is 2nd operand byte
incrScalarStkImm INT1
Incr scalar; scalar name is stktop; incr amount is op1. NEVER ISSUED.
incrArray1Imm LVT1 INT1
Incr array elem; array at slot op1 <= 255, elem is stktop, amount is 2nd operand byte
incrArrayStkImm INT1
Incr array element; elem is top then array name, amount is op1
incrStkImm INT1
Incr general variable; unparsed name is top, amount is op1
appendScalar1 LVT1
Append scalar variable at op1<=255 in frame; value is stktop
appendScalar4 LVT4
Append scalar variable at op1 > 255 in frame; value is stktop
appendArray1 LVT1
Append array element; array at op1<=255, value is top then elem
appendArray4 LVT4
Append array element; array at op1>=256, value is top then elem
appendArrayStk
Append array element; value is stktop, then elem, array names
appendStk
Append general variable; value is stktop, then unparsed name
Math Operations
Operations on values, usually expected to be numeric (and often enforced to be so, or even to be integers). Note that the numeric operations when applied to integers can work on any width of integer; 32-bit, 64-bit or arbitrary width (with the latter being at a penalty to performance).
lor
Logical or:
push (stknext || stktop)
land
Logical and:
push (stknext && stktop)
bitor
Bitwise or:
push (stknext | stktop)
bitxor
Bitwise xor
push (stknext ^ stktop)
bitand
Bitwise and:
push (stknext & stktop)
eq
Equal:
push (stknext == stktop)
neq
Not equal:
push (stknext != stktop)
lt
Less:
push (stknext < stktop)
gt
Greater:
push (stknext > stktop)
le
Less or equal:
push (stknext <= stktop)
ge
Greater or equal:
push (stknext >= stktop)
lshift
Left shift:
push (stknext << stktop)
rshift
Right shift:
push (stknext >> stktop)
add
Add:
push (stknext + stktop)
sub
Sub:
push (stkext - stktop)
mult
Multiply:
push (stknext * stktop)
div
Divide:
push (stknext / stktop)
mod
Mod:
push (stknext % stktop)
expon
Binary exponentiation operator:
push (stknext ** stktop)
uplus
Unary plus:
push +stktop
uminus
Unary minus:
push -stktop
bitnot
Bitwise not:
push ~stktop
not
Logical not:
push !stktop
tryCvtToNumeric
Try converting stktop to first int then double if possible.
numericType
Pushes the numeric type code of the word at the top of the stack.
Stack:
... value => ... typeCode
tryCvtToBoolean
Try converting stktop to boolean if possible. No errors.
Stack:
... value => ... value isStrictBool
List Operations
Note that the list opcode is also suitable for the construction of command callbacks.
foreach_start4 AUX4
Initialize execution of a foreach loop. Operand is aux data index of the ForeachInfo structure for the foreach command. OBSOLETE!
foreach_step4 AUX4
"Step" or begin next iteration of foreach loop. Push 0 if to terminate loop, else push 1. OBSOLETE!
foreach_start AUX4
Initialize execution of a foreach loop. Operand is aux data index of the ForeachInfo structure for the foreach command. It pushes 2 elements which hold runtime params for foreach_step, they are later dropped by foreach_end together with the value lists. NOTE that the iterator-tracker and info reference must not be passed to bytecodes that handle normal Tcl values. NOTE that this instruction jumps to the foreach_step instruction paired with it; the stack info below is only nominal.
Stack:
... listObjs... => ... listObjs... iterTracker info
foreach_step
"Step" or begin next iteration of foreach loop. Assigns to foreach iteration variables. May jump to straight after the foreach_start that pushed the iterTracker and info values. MUST be followed immediately by a foreach_end.
Stack:
... listObjs... iterTracker info => ... listObjs... iterTracker info
foreach_end
Clean up a foreach loop by dropping the info value, the tracker value and the lists that were being iterated over.
Stack:
... listObjs... iterTracker info => ...
lmap_collect
Appends the value at the top of the stack to the list located on the stack the "other side" of the foreach-related values.
Stack:
... collector listObjs... iterTracker info value => ... collector listObjs... iterTracker info
lappendScalar1 LVT1
Lappend scalar variable at op1<=255 in frame; value is stktop
lappendScalar4 LVT4
Lappend scalar variable at op1 > 255 in frame; value is stktop
lappendArray1 LVT1
Lappend array element; array at op1<=255, value is top then elem
lappendArray4 LVT4
Lappend array element; array at op1>=256, value is top then elem
lappendArrayStk
Lappend array element; value is stktop, then elem, array names
lappendStk
Lappend general variable; value is stktop, then unparsed name
lappendList LVT4
Lappend list to scalar variable at op4 in frame.
Stack:
... list => ... listVarContents
lappendListArray LVT4
Lappend list to array element; array at op4.
Stack:
... elem list => ... listVarContents
lappendListArrayStk
Lappend list to array element.
Stack:
... arrayName elem list => ... listVarContents
lappendListStk
Lappend list to general variable.
Stack:
... varName list => ... listVarContents
list UINT4
List:
push (stk1 stk2 ... stktop)
listIndex
List Index:
push (listindex stknext stktop)
listLength
List Len:
push (listlength stktop)
lindexMulti UINT4
Lindex with generalized args, operand is number of stacked objs used: (operand-1) entries from stktop are the indices; then list to process.
lsetList
Four-arg version of lset. stktop is old value; next is new element value, next is the index list; pushes new value
lsetFlat UINT4
Three- or >=5-arg version of lset, operand is number of stacked objs: stktop is old value, next is new element value, next come (operand-2) indices; pushes the new value.
listIndexImm IDX4
List Index:
push (lindex stktop op4)
listRangeImm IDX4 IDX4
List Range:
push (lrange stktop op4 op4)
listIn
List containment:
push [lsearch stktop stknext]>=0)
listNotIn
List negated containment:
push [lsearch stktop stknext]<0)
listConcat
Concatenates the two lists at the top of the stack into a single list and pushes that resulting list onto the stack.
Stack:
... list1 list2 => ... [lconcat list1 list2]
concatStk UINT4
Wrapper round
Tcl_ConcatObj()
, used forconcat
andeval
. opnd is number of values to concatenate.Operation:
push concat(stk1 stk2 ... stktop)
Dictionary Operations
Many dictionary operations take a key path (of fixed length); the keys can be arbitrary serializable values, as their UTF-8 string representation will be what is used for the key comparison. Operations that can create key/value pairs may retain a reference to a key (as well as to a value, more obviously).
dictGet UINT4
The top op4 words (min 1) are a key path into the dictionary just below the keys on the stack, and all those values are replaced by the value read out of that key-path (like
dict get
).Stack:
... dict key1 ... keyN => ... value
dictSet UINT4 LVT4
Update a dictionary value such that the keys are a path pointing to the value. op4#1 = numKeys, op4#2 = LVTindex
Stack:
... key1 ... keyN value => ... newDict
dictUnset UINT4 LVT4
Update a dictionary value such that the keys are not a path pointing to any value. op4#1 = numKeys, op4#2 = LVTindex
Stack:
... key1 ... keyN => ... newDict
dictIncrImm INT4 LVT4
Update a dictionary value such that the value pointed to by key is incremented by some value (or set to it if the key isn't in the dictionary at all). op4#1 = incrAmount, op4#2 = LVTindex
Stack:
... key => ... newDict
dictAppend LVT4
Update a dictionary value such that the value pointed to by key has some value string-concatenated onto it. op4 = LVTindex
Stack:
... key valueToAppend => ... newDict
dictLappend LVT4
Update a dictionary value such that the value pointed to by key has some value list-appended onto it. op4 = LVTindex
Stack:
... key valueToAppend => ... newDict
dictFirst LVT4
Begin iterating over the dictionary, using the local scalar indicated by op4 to hold the iterator state. The local scalar should not refer to a named variable as the value is not wholly managed correctly.
Stack:
... dict => ... value key doneBool
dictNext LVT4
Get the next iteration from the iterator in op4's local scalar.
Stack:
... => ... value key doneBool
dictDone LVT4
Terminate the iterator in op4's local scalar. Use unsetScalar instead (with 0 for flags).
dictUpdateStart LVT4 AUX4
Create the variables (described in the aux data referred to by the second immediate argument) to mirror the state of the dictionary in the variable referred to by the first immediate argument. The list of keys (top of the stack, not poppsed) must be the same length as the list of variables.
Stack:
... keyList => ... keyList
dictUpdateEnd LVT4 AUX4
Reflect the state of local variables (described in the aux data referred to by the second immediate argument) back to the state of the dictionary in the variable referred to by the first immediate argument. The list of keys (popped from the stack) must be the same length as the list of variables.
Stack:
... keyList => ...
dictExpand
Probe into a dict and extract it (or a subdict of it) into variables with matched names. Produces list of keys bound as result. Part of
dict with
.Stack:
... dict path => ... keyList
dictRecombineStk
Map variable contents back into a dictionary in a variable. Part of
dict with
.Stack:
... dictVarName path keyList => ...
dictRecombineImm LVT4
Map variable contents back into a dictionary in the local variable indicated by the LVT index. Part of
dict with
.Stack:
... path keyList => ...
dictExists UINT4
The top op4 words (min 1) are a key path into the dictionary just below the keys on the stack, and all those values are replaced by a boolean indicating whether it is possible to read out a value from that key-path (like
dict exists
).Stack:
... dict key1 ... keyN => ... boolean
verifyDict
Verifies that the word on the top of the stack is a dictionary, popping it if it is and throwing an error if it is not.
Stack:
... value => ...
Introspection Operations
currentNamespace
Push the name of the interpreter's current namespace as an object on the stack.
infoLevelNumber
Push the stack depth (i.e.,
info level
) of the interpreter as an object on the stack.
infoLevelArgs
Push the argument words to a stack depth (i.e.,
info level <n>
) of the interpreter as an object on the stack.Stack:
... depth => ... argList
resolveCmd
Resolves the command named on the top of the stack to its fully qualified version, or produces the empty string if no such command exists. Never generates errors.
Stack:
... cmdName => ... fullCmdName
originCmd
Reports which command was the origin (via namespace import chain) of the command named on the top of the stack.
Stack:
... cmdName => ... fullOriginalCmdName
coroName
Push the name of the interpreter's current coroutine as an object on the stack.
TclOO Operations
Most of TclOO is either normal evaluation of something like a procedure (with appropriate resolvers set up) or standard NRE-aware command interpretation. Only a few selected operations are implemented differently.
tclooSelf
Push the identity of the current TclOO object (i.e., the name of its current public access command) on the stack.
tclooClass
Push the class of the TclOO object named at the top of the stack onto the stack.
Stack:
... object => ... class
tclooNamespace
Push the namespace of the TclOO object named at the top of the stack onto the stack.
Stack:
... object => ... namespace
tclooIsObject
Push whether the value named at the top of the stack is a TclOO object (i.e., a boolean). Can corrupt the interpreter result despite not throwing, so not safe for use in a post-exception context.
Stack:
... value => ... boolean
tclooNext UINT1
Call the next item on the TclOO call chain, passing opnd arguments (min 1, max 255, includes "
next
"). The result of the invoked method implementation will be pushed on the stack in place of the arguments (similar to invokeStk).Stack:
... "next" arg2 arg3 -- argN => ... result
tclooNextClass UINT1
Call the following item on the TclOO call chain defined by class className, passing opnd arguments (min 2, max 255, includes "
nextto
" and the class name). The result of the invoked method implementation will be pushed on the stack in place of the arguments (similar to invokeStk).Stack:
... "nextto" className arg3 arg4 -- argN => ... result
Array Operations
These operations are used to support Tcl's array
command.
arrayExistsStk
Looks up the element on the top of the stack and tests whether it is an array. Pushes a boolean describing whether this is the case. Also runs the whole-array trace on the named variable, so can throw anything.
Stack:
... varName => ... boolean
arrayExistsImm UINT4
Looks up the variable indexed by opnd and tests whether it is an array. Pushes a boolean describing whether this is the case. Also runs the whole-array trace on the named variable, so can throw anything.
Stack:
... => ... boolean
arrayMakeStk
Forces the element on the top of the stack to be the name of an array.
Stack:
... varName => ...
arrayMakeImm UINT4
Forces the variable indexed by opnd to be an array. Does not touch the stack.