Standard Tcl Bytecodes

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 or TCL_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 for concat and eval. 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.