Koskari bytecode
The instruction set of the Koskari evaluator: what a compiled code object
holds, how the evaluator runs it, and one section per opcode with its
stack effect, invariants, and a disassembly. The evaluator itself is
koskari.lib; the compiler that emits this bytecode is koskari.compile;
koskari.dis disassembles a code object into the tables shown here.
1. The evaluator
1.1 Model
A compiled function or expression is a code object (KosCode): a
fixed array of (opcode, arg) instructions, a constant pool, an extent
table describing its blocks, a position table mapping instructions back
to source, and an extra table for the few opcodes whose argument is a
tuple. Instructions are addressed by index, the pc.
The evaluator is stackless. A Koskari call does not consume the C stack: each running code object has a frame on the heap with an operand stack, and calls, returns, yields, awaits, and continuation jumps move between frames without recursion in C. That is what lets tail calls loop, deep recursion run, and any function suspend.
Alongside the operand stack the evaluator keeps a dynamic chain of
nodes: one per active frame, loop, try, finally, namespace, context
manager, prompt, continuation capture, dynamic-wind extent, and
parameterize extent. PUSH_* opcodes push a node and POP_* and
CLEAR_* opcodes pop one. Exceptions, break, return, and
continuation invocations walk the chain to find where control goes and
what must run on the way.
Names resolve through namespaces. A VAR* opcode names a variable by
constant-pool index and looks it up through the frame’s namespace chain;
convert_fast lowers a name with a fixed slot to its FAST* twin, which
indexes the frame’s local slots directly.
1.2 Notation
Stack:
[a, b, c]with TOS, the top of stack, on the right. “Below TOS” is the second element.Stack effect: written as before and after, for example
[..., callable, a, b] -> [..., result].Chain: an opcode that pushes or pops a dynamic chain node says so under Pushes or Pops, with the node kind and, where relevant, the static extent kind.
Anchors: each opcode heading is
### KOS_OP_NAME, so#kos_op_namelinks to it from the per-opcode pages and elsewhere.
1.3 Glossary
bind: establish or replace the mapping from a name to a ref. See 1.9.
store: write a value through the ref that already resolves a name. See 1.9.
pc: the instruction index.
TOS: the top of the operand stack.
cpool: the constant pool, the code object’s read-only array of constants and names, indexed as
cpool[i].RAW (field kind): an EXTRA row field holding a number the instruction interprets itself, such as
CHECK_COMPARE’s negate flag or a matcher instruction’s stack depth, width, count, flag or core type ordinal. Finalize leaves it unchanged.extent: a statically described block in the code object’s extent table, with a kind (
KOS_EXT_TRY,KOS_EXT_LOOP,KOS_EXT_FOREACH,KOS_EXT_PROMPT,KOS_EXT_NS,KOS_EXT_COLLECT, and others), enter and exit pcs, and kind-specific targets.dynamic chain: the runtime chain of nodes. The node kinds are the
KosDynKindenum inkoskari/lib/dynchain.h, in enum order:KOS_DYN_FRAME– function activation record.KOS_DYN_PROMPT– delimiter for delimited continuations (reset).KOS_DYN_DELIM– return marker for a delimited invoke, carrying the return metadata.KOS_DYN_WIND– dynamic-wind extent with before and after hooks.KOS_DYN_TRY– try region.KOS_DYN_FINALLY– finally region.KOS_DYN_LOOP– loop region.KOS_DYN_FOREACH– foreach region.KOS_DYN_NS– namespace scope, pushed byPUSH_NSand popped byPOP_NS.KOS_DYN_COLLECT– collector scope (PUSH_COLLECT/POP_COLLECT), which pushes its namespace on pop.KOS_DYN_CC– undelimited continuation block (call/cc).KOS_DYN_PARAM– parameter bindings for a parameterize extent.KOS_DYN_WITH– context manager (withanddyn-with). Single-shot versus multi-shot is a field on the node, not a second kind.KOS_DYN_SHIFT– shift handler bookmark. Owns the handler body’s operand segment; no frame or namespace of its own.KOS_DYN_GEN– generator node. Intercepts yield, return, and raise, and denies shift.KOS_DYN_UNKNOWN– sentinel past the last kind; never a live node.
pre-compile, post-compile: the instruction stream as the compiler emits it, with labels as strings and constants as values, and the bytecode after finalize, with labels as pcs and values as pool indices. See 1.7.
safety net:
LABELandPOSITIONare stripped by finalize; if one survives it executes as a no-op that advances the pc.
1.4 Disassembly tables
A disassembly in this document is a table with five columns:
Column |
Meaning |
|---|---|
index |
the instruction’s pc |
opcode |
the opcode name |
arg |
the raw argument, a uint16 |
arg view |
the decoded argument: a constant as |
comment |
the stack before the instruction, or its control-flow effect |
Tables are post-compile unless marked otherwise.
1.5 Invariants
Unless an opcode’s section says otherwise:
Jump locality: a jump opcode (
JUMP,JUMP_FALSE,JUMP_TRUE,JUMP_AND,JUMP_OR,ITER_NEXT,CHECK_*) targets a pc inside the current extent or the extent’spop_pc, which leaves the block.
The Invariants bullets under each opcode, with this list, are the contract between compiler and evaluator: the compiler emits code that satisfies them and the evaluator relies on them. A violation is undefined behaviour, asserted in debug builds.
1.6 Implementation status
Every opcode has a runtime handler except THEEND, the end-of-code
sentinel, which raises if executed. LABEL and POSITION exist only in
the pre-compile stream and are stripped by finalize. This document is
the record of that status; a new opcode is added to opcodes.incl,
given a handler, and given a section here.
1.7 Compilation: pre-compile and post-compile
The compiler emits a pre-compile stream of instructions, and a
finalize pass produces the post-compile bytecode stored in the
code object: labels become pcs, values become constant-pool indices,
the extent and position tables are derived, and VAR may lower to
FAST. Finalize is distinct from Compiler.compress, the earlier
peephole pass over the instruction list described in 1.8. Many opcodes
mean something different by their argument in each form.
Pipeline
Pre-compile stream: Pairs of (opcode, arg). Labels are str or int names. Constants and names may appear as literal values (e.g.
CONST "hello",VAR "x"). LABEL and POSITION may be present.Finalize: Resolve labels to instruction indices (pcs). Build the constant pool from in-line values and assign indices. Rewrite CONST, VAR, ATTR, and other name/key operands to pool indices. Optionally lower VAR to FAST for names that have a fixed slot. Derive extent and position tables. LABEL/POSITION may be rewritten to NOOP or retained with unused arg.
Post-compile (bytecode): Fixed (op, arg) per instruction; branch args are pcs; constant/name args are pool indices or slot indices. This is what the evaluator executes and what disassembly tables in this document show.
Argument mappings
Pre-compile arg |
Post-compile arg |
Opcodes (examples) |
|---|---|---|
str or int label name |
pc (uint16) |
JUMP, JUMP_FALSE, JUMP_TRUE, JUMP_AND, JUMP_OR, ITER_NEXT, CHECK_*, PUSH_TRY, PUSH_FINALLY, PUSH_WIND |
Literal value |
Constant pool index |
CONST |
Name (string/symbol) |
Constant pool index |
VAR, VAR_BIND, VAR_CLEAR, VAR_TAKE, VAR_REF, VAR_STORE; ATTR*, ITEM_CONST* (key) |
|
Extra-table index |
VAR_STORE_CONST (section 12); may lower to FAST_STORE_CONST (section 13) |
Name -> slot (optional) |
Fast local index |
VAR may be lowered to FAST*; then arg is slot index |
(unchanged) |
(unchanged) |
NOARG, COUNT, etc. |
0 (no arg; break target derived at runtime from extent table |
0 (unused) |
PUSH_FOREACH, PUSH_LOOP |
Compile-time only: LABEL and POSITION are omitted in the post-compile bytecode under normal circumstances. Finalize strips them and adjusts any branch targets that pointed at a stripped instruction. Position data from POSITION is recorded in the code object’s position table only. If a LABEL or POSITION is retained (e.g. by a different code path), it has a cursory no-op implementation as a safety net; at runtime it advances PC only.
Where the pre form differs from the bytecode form, opcode sections below include a Compiler form line. Disassembly tables are post-compile unless marked otherwise.
1.8 Peephole compression: Compiler.compress
The compiler runs Compiler.compress over a fragment’s instruction list
inside Compiler.complete, before the constant-pool merge,
convert_fast, demote_tail_calls_if_yields, and construction of the
code object. The implementation is compress, _CHECK_SQUASHES, and
_SWITCH_SQUASHES in koskari/compile/compiler.py; the tests are in
tests/compile/test_compress.py.
Purpose. Shorten or simplify the pre-finalize (opcode, arg) stream in a
single forward pass. The pass keeps a short output deque; most rules compare the
current instruction with the last emitted one (squished[-1]). The
implementation seeds the deque with a leading KOS_OP_NOOP and drops it at
the end if any real instructions were emitted.
Non-goals. compress does not resolve labels to PCs, build the constant
pool, derive extent or position tables, lower VAR to FAST (convert_fast),
or demote tail calls when yields are present. Those happen later; see section 1.7.
Transformations (order matches the for (op, arg) in instr branch order in
compress):
Category |
Rule |
|---|---|
Dead stack |
|
Constant fold |
|
Constant + |
Prior |
Constant + |
Prior |
Compare + |
Prior opcode is in |
|
Prior opcode in |
|
If the |
Implicit |
|
Built tuple |
|
|
Two consecutive same opcodes |
|
Prior |
Epilogue |
If the stream does not end with |
Control feeder (fusion pass) |
In the later |
Truth-test feeder (fusion pass) |
In the later |
Short-circuit feeder (fusion pass) |
In the later |
Item feeders (fusion pass) |
In the later |
_CHECK_SQUASHES (prior opcode -> LABEL opcode replacing the JUMP_FALSE pair; the fused opcode inherits the jump’s label):
Prior |
Replaced with |
|---|---|
|
|
|
|
|
|
OBJECT_COMPARE fusion (selector-keyed comparison prior -> EXTRA (CMP, COUNT, LABEL, RAW) check). The prior KOS_OP_OBJECT_COMPARE carries its selector and operand count in a CMPCOUNT arg; the fusion preserves both, emitting KOS_OP_CHECK_COMPARE with arg (selector, count, label, 0) so the chained comparison survives (a < b < c fuses just like a < b); the JUMP_TRUE pair fuses the same way with the fourth field, the negate flag, set to 1, so the check tests the negated chain.
_SWITCH_SQUASHES (prior opcode -> fused switch opcode):
Prior |
Replaced with |
|---|---|
|
|
|
|
|
|
Examples.
KOS_OP_OBJECT_COMPARE(EQ, count),KOS_OP_JUMP_FALSEL-> oneKOS_OP_CHECK_COMPARE(EQ, count, L, 0)(selector and count carried from the comparison, label from the jump).KOS_OP_OBJECT_COMPARE(EQ, count),KOS_OP_JUMP_TRUEL-> oneKOS_OP_CHECK_COMPARE(EQ, count, L, 1), which jumps when the chain holds.
1.9 Bind and store
Two opcode families write to a name, and they do different things.
Operation |
Meaning |
|---|---|
bind |
establish or replace the mapping from the name to a ref; from now on the name resolves to this ref |
store |
write a value through the ref the name already resolves to; the name must already be bound |
VAR_BIND and FAST_BIND introduce or rebind a name. VAR_STORE and
FAST_STORE update the value at an existing binding. When the stored
value is a constant, Compiler.compress fuses CONST and VAR_STORE
into VAR_STORE_CONST, which uses no stack, and convert_fast lowers
that to FAST_STORE_CONST for a local. The same split is the surface
distinction between var and set!; see
Bindings and refs.
2. Opcode families
The opcodes by family, each linking to its section.
3. No-op and compile-time – NOOP, LABEL, POSITION
4. Stack – DUP, POP, UNPACK, UNPACK_STAR, UNPACK_VAR, UNPACK_FAST
5. Constants – CONST, CONST2, CONST3, CONST4
5.1 Pair construction and access – CAR, CDR, CONS, PROPER, PAIR_SPLICE, BRACKET_SPLICE
6. Mode control – AWAIT, BREAK, CONTINUE, RAISE, RETURN, YIELD, RETURN_CONST, YIELD_CONST, YIELD_FROM
7. Iteration – ITER_NEXT, ITER_NEXT_STORE_VAR, ITER_NEXT_STORE_FAST, OBJECT_NEXT, VAR_NEXT, FAST_NEXT
8. Jumps – JUMP, JUMP_FALSE, JUMP_TRUE, JUMP_FALSE_VAR, JUMP_TRUE_VAR, JUMP_FALSE_FAST, JUMP_TRUE_FAST, JUMP_AND, JUMP_OR, JUMP_AND_VAR, JUMP_OR_VAR, JUMP_AND_FAST, JUMP_OR_FAST
9. Check jumps – CHECK_COMPARE, CHECK_COMPARE_VAR, CHECK_COMPARE_FAST, CHECK_EXCEPTION
9.1 Switch dispatch – SWITCH_EQ, SWITCH_EQ_CONST, SWITCH_EQ_VAR, SWITCH_EQ_FAST, SWITCH_EQ_VAR_ATTR, SWITCH_EQ_FAST_ATTR
9.2 Pattern matching – MATCH_DESCEND, MATCH_SINGLE, MATCH_FITS, MATCH_NEXT, MATCH_BOUND, MATCH_UNBOUND, MATCH_SYNC, MATCH_TAIL, MATCH_SCOPE, MATCH_SCOPE_NEXT, MATCH_RESET, MATCH_AT, MATCH_SPAN, MATCH_STORE, MATCH_CLEAR, MATCH_CAPTURES, MATCH_PASS, MATCH_LOAD, MATCH_APPEND, MATCH_MIN, MATCH_COLUMNS, MATCH_LITERAL, MATCH_CORE, MATCH_TYPE_VAR, MATCH_TYPE_FAST, MATCH_CLASS_VAR, MATCH_CLASS_FAST, MATCH_SAME, MATCH_FIELD_POS_VAR, MATCH_FIELD_POS_FAST, MATCH_FIELD_KW, MATCH_MAPPING, MATCH_KEY, MATCH_KEY_VAR, MATCH_KEY_FAST
10. Introspection – GLOBALS, LOCALS, IMPORT, IMPORT_FROM, IMPORT_STAR
11. Exception handling – EXCEPTION, EXCEPTION_CLEAR, EXCEPTION_MATCH
12. Variables by name – VAR, VAR2, VAR3, VAR4, VAR_BIND, VAR_CLEAR, VAR_CLEAR2/3/4, VAR_REF, VAR_STORE, VAR_STORE_CONST, VAR_ATTR*, VAR_ITEM*, VAR_ITER, VAR_NEXT, VAR_FORMAT, VAR_FORMAT_CONST, RETURN_VAR, YIELD_VAR
13. Fast variables – FAST, FAST2, FAST3, FAST4, FAST_BIND, FAST_CLEAR, FAST_CLEAR2/3/4, FAST_REF, FAST_STORE, FAST_STORE_CONST, FAST_ATTR*, FAST_ITEM*, FAST_ITER, FAST_NEXT, FAST_FORMAT, FAST_FORMAT_CONST, RETURN_FAST, YIELD_FAST
14. Attributes – ATTR, ATTR_CLEAR, ATTR_REF, ATTR_STORE
15. Items – ITEM, ITEM_STORE, ITEM_INPLACE, ITEM_CLEAR, ITEM_TAKE, ITEM_REF, and the rows naming their object, key, and value
15.1 Reference dereference – DEREF
16. Argument production – BUILD_ARGS, BUILD_FUNCTION, BUILD_KWDS, etc.
17. Calls – CALL, CALL_NAMES, CALL_STAR, CALL_ATTR*, TAIL_*
18. Block control – PUSH_FOREACH, PUSH_LOOP, PUSH_NS, PUSH_COLLECT, PUSH_TRY, PUSH_FINALLY, CLEAR_, POP_
18.1 Context managers (with / dyn-with) – PUSH_WITH, POP_WITH, PUSH_DYN_WITH, POP_DYN_WITH
19. Object protocol – OBJECT_* (comparisons, predicates, numeric, general)
20. Delimited continuations – PUSH_PROMPT, PUSH_SHIFT, POP_SHIFT, POP_PROMPT
21. Undelimited continuations (call/cc) – PUSH_CC, POP_CC, CAPTURE_CC
22. Dynamic wind – PUSH_WIND, POP_WIND
23. Parameterize extent – PUSH_PARAM, PARAM, POP_PARAM
24. Sentinel – THEEND
2.1 Quick reference
Opcode |
Style |
One-line effect |
Section |
|---|---|---|---|
NOOP |
NOARG |
Advance PC only |
|
LABEL |
COMPILE |
Jump target; stripped post-compile |
|
POSITION |
COMPILE |
Source position; stripped post-compile |
|
DUP |
COUNT |
Duplicate top N stack elements |
|
POP |
COUNT |
Pop N elements |
|
UNPACK |
COUNT |
Realize TOS as list; push N scalars (seq[0] is TOS) |
|
UNPACK_STAR |
EXTRA |
Prefix / middle / suffix unpack (two COUNT fields) |
|
UNPACK_VAR |
EXTRA |
STORE seq[0], seq[1] into two VAR names |
|
UNPACK_FAST |
EXTRA |
STORE seq[0], seq[1] into two fast slots |
|
CONST |
CONST |
Push constant from pool |
|
CONST2 |
EXTRA |
Push two constants in row order |
|
CONST3 |
EXTRA |
Push three constants in row order |
|
CONST4 |
EXTRA |
Push four constants in row order |
|
CAR |
COUNT |
Apply car n times (n >= 1); n = 0 invalid |
|
CDR |
COUNT |
Apply cdr n times (n >= 1); n = 0 invalid |
|
CONS |
COUNT |
Pop N values; push (e_0 . … . e_{N-1}) |
|
PROPER |
COUNT |
Pop N values; push proper list (e_0 … e_{N-1}) |
|
BRACKET_CONS |
COUNT |
Pop N values; push the bracket pair chain [e_0 . … . e_{N-1}] |
|
BRACKET_PROPER |
COUNT |
Pop N values; push the proper bracket list [e_0 … e_{N-1}] |
|
PAIR_SPLICE |
EXTRA |
Concatenate pair/tuple segments into one list ending in nil or a stacked tail |
|
BRACKET_SPLICE |
EXTRA |
Concatenate pair/tuple segments into one list with a bracket leading cell, ending in nil or a stacked tail |
|
AWAIT |
COUNT |
Suspend on awaitable; resume with value |
|
BREAK |
COUNT |
Jump to loop break target |
|
CONTINUE |
COUNT |
Jump to loop continue target |
|
RAISE |
COUNT |
Pop N, raise exception |
|
RETURN |
COUNT |
Pop the return value and deliver it to the frame’s parent or the host |
|
YIELD |
COUNT |
Pop the value and suspend the frame, delivering it to the consumer |
|
RETURN_CONST |
CONST |
Return the pooled constant; the |
|
YIELD_CONST |
CONST |
Yield the pooled constant; the |
|
YIELD_FROM |
NOARG |
Delegate to sub-iterator/gen; PC-stable; send/throw/close |
|
ITER_NEXT |
LABEL |
Next from region iterator; else jump |
|
ITER_NEXT_STORE_VAR |
EXTRA |
Next from region iterator stored under the name; else jump; the |
|
ITER_NEXT_STORE_FAST |
EXTRA |
Next from region iterator stored into the fast slot; else jump |
|
OBJECT_NEXT |
COUNT |
Stack-based next (1 or 2 args) |
|
JUMP |
LABEL |
Unconditional jump to pc |
|
JUMP_FALSE |
LABEL |
Jump if TOS false |
|
JUMP_TRUE |
LABEL |
Jump if TOS true |
|
JUMP_FALSE_VAR |
EXTRA |
Jump if the named value is false |
|
JUMP_TRUE_VAR |
EXTRA |
Jump if the named value is true |
|
JUMP_FALSE_FAST |
EXTRA |
Jump if the fast slot is false |
|
JUMP_TRUE_FAST |
EXTRA |
Jump if the fast slot is true |
|
NILP |
NOARG |
Pop TOS; push True when it is an empty-list singleton |
|
CHECK_NIL |
LABEL |
Pop TOS; jump when it is not an empty-list singleton |
|
JUMP_AND |
LABEL |
Short-circuit AND |
|
JUMP_OR |
LABEL |
Short-circuit OR |
|
JUMP_AND_VAR |
EXTRA |
Short-circuit AND over the named value |
|
JUMP_OR_VAR |
EXTRA |
Short-circuit OR over the named value |
|
JUMP_AND_FAST |
EXTRA |
Short-circuit AND over the fast slot |
|
JUMP_OR_FAST |
EXTRA |
Short-circuit OR over the fast slot |
|
CHECK_COMPARE |
EXTRA |
Chain-compare N operands under a KosCompare selector; jump if chain fails |
|
CHECK_COMPARE_VAR |
EXTRA |
Arity-2 fused check; operands from VAR/CONST per CMPSRC bits |
|
CHECK_COMPARE_FAST |
EXTRA |
Arity-2 fused check; operands from FAST/CONST per CMPSRC bits |
|
CHECK_EXCEPTION |
LABEL |
Jump if exception no match |
|
SWITCH_EQ |
LABEL |
Equality dispatch; on match pop both and jump; on mismatch pop key only, fall through |
|
SWITCH_EQ_CONST |
EXTRA |
Compare TOS to constant RHS; on match pop TOS and jump; on mismatch fall through |
|
SWITCH_EQ_VAR |
EXTRA |
Compare TOS to namespace var RHS; on match pop TOS and jump; on mismatch fall through |
|
SWITCH_EQ_FAST |
EXTRA |
Compare TOS to fast-slot RHS; on match pop TOS and jump; on mismatch fall through |
|
SWITCH_EQ_VAR_ATTR |
EXTRA |
Compare TOS to getattr(var, attr); on match pop TOS and jump; on mismatch fall through |
|
SWITCH_EQ_FAST_ATTR |
EXTRA |
Compare TOS to getattr(fast, attr); on match pop TOS and jump; on mismatch fall through |
|
MATCH_DESCEND |
LABEL |
Sequence gate on TOS; a cursor over it replaces it; a miss pops it |
|
MATCH_SINGLE |
NOARG |
A one-element cursor over TOS replaces it |
|
MATCH_FITS |
EXTRA |
Miss unless the cursor at the depth has between the minimum and the maximum elements left |
|
MATCH_NEXT |
EXTRA |
Pull the next element from the cursor at the depth, boxed from a pair spine; a miss at the end |
|
MATCH_BOUND |
EXTRA |
Push a cursor at the cursor’s position ending the width before its end |
|
MATCH_UNBOUND |
EXTRA |
Push a cursor at the cursor’s position ending at its subject’s end |
|
MATCH_SYNC |
EXTRA |
Move the cursor at the first depth to the position of the cursor at the second |
|
MATCH_TAIL |
EXTRA |
Push the remaining elements but the suffix width as a span, advancing the cursor |
|
MATCH_SCOPE |
EXTRA |
Push a mark at the cursor’s position with the count of empty slots |
|
MATCH_SCOPE_NEXT |
EXTRA |
Push a mark at the cursor’s position, then the cursor’s next element; a miss leaves the mark |
|
MATCH_RESET |
EXTRA |
Move the cursor at the first depth back to the position of the mark at the second |
|
MATCH_AT |
EXTRA |
Push the element at the mark’s position |
|
MATCH_SPAN |
EXTRA |
Push the span from the mark to the cursor; jump when it is empty |
|
MATCH_STORE |
EXTRA |
Pop TOS into a slot of the mark at the depth |
|
MATCH_CLEAR |
EXTRA |
Empty the listed slots of the mark at the depth |
|
MATCH_CAPTURES |
EXTRA |
Push the mark’s filled slots: a DatumFrame over a pair spine, a dict otherwise |
|
MATCH_PASS |
EXTRA |
Push a repeat pass’s value: its captures, or its span when no slot is filled |
|
MATCH_LOAD |
EXTRA |
Push a slot of the mark at the depth; jump when it is empty |
|
MATCH_APPEND |
EXTRA |
Pop TOS and append it to the list at the depth |
|
MATCH_MIN |
EXTRA |
Miss unless the list at the depth holds at least the count of items |
|
MATCH_COLUMNS |
EXTRA |
Store each name’s per-pass values, as a list, into a slot of the mark |
|
MATCH_LITERAL |
EXTRA |
TOS, which stays, must be the constant |
|
MATCH_CORE |
EXTRA |
TOS, which stays, must be an instance of the core type the ordinal names |
|
MATCH_TYPE_VAR / MATCH_TYPE_FAST |
EXTRA |
TOS, which stays, must be an instance of the type in the variable |
|
MATCH_CLASS_VAR / MATCH_CLASS_FAST |
EXTRA |
TOS, which stays, must be an instance of the class in the variable, whose |
|
MATCH_SAME |
EXTRA |
TOS, which stays, must equal a slot of the mark at the depth; an empty slot misses |
|
MATCH_FIELD_POS_VAR / MATCH_FIELD_POS_FAST |
EXTRA |
Push the attribute the class’s |
|
MATCH_FIELD_KW |
EXTRA |
Push the attribute the constant names |
|
MATCH_MAPPING |
LABEL |
The mapping gate on TOS |
|
MATCH_KEY |
EXTRA |
Push the value under the constant key; an absent key misses |
|
MATCH_KEY_VAR / MATCH_KEY_FAST |
EXTRA |
Push the value under the key in the variable; an absent key misses |
|
GLOBALS |
NOARG |
Push globals dict |
|
LOCALS |
NOARG |
Push locals dict |
|
IMPORT |
EXTRA |
Import module; bind root or leaf (self-contained) |
|
IMPORT_FROM |
EXTRA |
Import module; bind named attrs (self-contained) |
|
IMPORT_STAR |
EXTRA |
Import module; bind its public names |
|
IMPORT_USE |
EXTRA |
Import the leaf module; probe each feature stem’s candidates and bind every hit under the parallel stem |
|
EXCEPTION |
NOARG |
Push current exception |
|
EXCEPTION_CLEAR |
NOARG |
Clear exception state |
|
EXCEPTION_MATCH |
NOARG |
Pop type(s), push match result |
|
VAR |
VAR |
Load by name |
|
VAR2 |
EXTRA |
Load two names, push in row order |
|
VAR3 |
EXTRA |
Load three names, push in row order |
|
VAR4 |
EXTRA |
Load four names, push in row order |
|
VAR_BIND |
VAR |
BIND: use TOS ref to resolve name |
|
VAR_CLEAR |
VAR |
Delete the name from the namespace; no stack effect |
|
VAR_CLEAR2 |
EXTRA |
Clear 2 names in row order; no stack effect |
|
VAR_CLEAR3 |
EXTRA |
Clear 3 names in row order; no stack effect |
|
VAR_CLEAR4 |
EXTRA |
Clear 4 names in row order; no stack effect |
|
VAR_TAKE |
VAR |
Deref the name, clear the binding, push the value; NameError when the binding is empty |
|
VAR_REF |
VAR |
Push a reference to the named variable |
|
VAR_STORE |
VAR |
STORE: write TOS value into name |
|
VAR_STORE_CONST |
EXTRA |
STORE: write constant into name (no stack) |
|
VAR_INPLACE |
EXTRA |
Augmented assignment through the namespace: deref the name, reduce with the popped rhs, store back |
|
VAR_INPLACE_CONST |
EXTRA |
Augmented assignment through the namespace with a constant rhs; no stack effect |
|
VAR_ATTR |
EXTRA |
Get attribute; object loaded from the namespace by name |
|
VAR_ATTR_STORE |
EXTRA |
Set attribute; object from the namespace |
|
VAR_ATTR_CLEAR |
EXTRA |
Delete attribute; object from the namespace |
|
VAR_ATTR_TAKE |
EXTRA |
Get attribute, delete it, push the value; object from the namespace |
|
VAR_ATTR_REF |
EXTRA |
Push attribute reference; object from the namespace |
|
VAR_ATTR_INPLACE |
EXTRA |
Reduce obj.attr in place with the count values and store it back; object from the namespace |
|
VAR_ITER |
VAR |
Fused VAR + OBJECT_ITER: push the named iterable’s iterator |
|
VAR_NEXT |
EXTRA |
Fused VAR + OBJECT_NEXT: step the named iterator; count 2 pops a default for exhaustion |
|
VAR_FORMAT |
VAR |
Fused VAR + OBJECT_FORMAT: push |
|
VAR_FORMAT_CONST |
EXTRA |
Fused VAR + OBJECT_FORMAT_CONST: format the named object with pooled rules |
|
RETURN_VAR |
VAR |
Return the name’s value; the |
|
YIELD_VAR |
VAR |
Yield the name’s value; the |
|
FAST |
FASTVAR |
Load from slot |
|
FAST2 |
EXTRA |
Load two slots, push in row order |
|
FAST3 |
EXTRA |
Load three slots, push in row order |
|
FAST4 |
EXTRA |
Load four slots, push in row order |
|
FAST_BIND |
FASTVAR |
BIND: use TOS ref to resolve slot |
|
FAST_CLEAR |
FASTVAR |
Clear the slot; no stack effect |
|
FAST_CLEAR2 |
EXTRA |
Clear 2 slots in row order; no stack effect |
|
FAST_CLEAR3 |
EXTRA |
Clear 3 slots in row order; no stack effect |
|
FAST_CLEAR4 |
EXTRA |
Clear 4 slots in row order; no stack effect |
|
FAST_TAKE |
FASTVAR |
Take the slot’s value and clear it; NameError when the slot is empty |
|
FAST_REF |
FASTVAR |
Push a reference to the slot |
|
FAST_STORE |
FASTVAR |
STORE: write TOS value into slot |
|
FAST_STORE_CONST |
EXTRA |
STORE: write constant into slot (no stack) |
|
FAST_INPLACE |
EXTRA |
Augmented assignment on a slot: deref, reduce with the popped rhs, store back |
|
FAST_INPLACE_CONST |
EXTRA |
Augmented assignment on a slot with a constant rhs; no stack effect |
|
FAST_ATTR |
EXTRA |
Get attribute; object from a fast slot |
|
FAST_ATTR_STORE |
EXTRA |
Set attribute; object from a fast slot |
|
FAST_ATTR_CLEAR |
EXTRA |
Delete attribute; object from a fast slot |
|
FAST_ATTR_TAKE |
EXTRA |
Get attribute, delete it, push the value; object from a fast slot |
|
FAST_ATTR_REF |
EXTRA |
Push attribute reference; object from a fast slot |
|
FAST_ATTR_INPLACE |
EXTRA |
Reduce obj.attr in place with the count values and store it back; object from a fast slot |
|
FAST_ITER |
FASTVAR |
As VAR_ITER, with the iterable loaded from its fast slot |
|
FAST_NEXT |
EXTRA |
As VAR_NEXT, with the iterator loaded from its fast slot |
|
FAST_FORMAT |
FASTVAR |
As VAR_FORMAT, with the object loaded from its fast slot |
|
FAST_FORMAT_CONST |
EXTRA |
As VAR_FORMAT_CONST, with the object loaded from its fast slot |
|
RETURN_FAST |
FASTVAR |
Return the slot’s value; lowering of RETURN_VAR |
|
YIELD_FAST |
FASTVAR |
Yield the slot’s value; lowering of YIELD_VAR |
|
ATTR |
CONST |
Get attribute |
|
ATTR_STORE |
CONST |
Set attribute |
|
ATTR_CLEAR |
CONST |
Delete attribute |
|
ATTR_TAKE |
CONST |
Get attribute, delete it, push the value |
|
ATTR_REF |
CONST |
Push attribute reference |
|
ATTR_INPLACE |
EXTRA |
Reduce obj.attr in place with the count values and store it back; pushes nothing |
|
ITEM |
NOARG |
Get item; object on the stack, key on the stack |
|
ITEM_CLEAR |
NOARG |
Delete item; object on the stack, key on the stack |
|
ITEM_TAKE |
NOARG |
Take item; object on the stack, key on the stack |
|
ITEM_REF |
NOARG |
Item reference; object on the stack, key on the stack |
|
ITEM_STORE |
NOARG |
Set item; object on the stack, key on the stack |
|
ITEM_STORE_CONST |
CONST |
Set item to a constant; object on the stack, key on the stack |
|
ITEM_STORE_VAR |
VAR |
Set item; object on the stack, key on the stack, value by name |
|
ITEM_STORE_FAST |
FASTVAR |
Set item; object on the stack, key on the stack, value from a fast slot |
|
ITEM_INPLACE |
OPCOUNT |
Reduce item in place; object on the stack, key on the stack |
|
ITEM_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object on the stack, key on the stack |
|
ITEM_CONST |
CONST |
Get item; object on the stack, constant key |
|
ITEM_CONST_CLEAR |
CONST |
Delete item; object on the stack, constant key |
|
ITEM_CONST_TAKE |
CONST |
Take item; object on the stack, constant key |
|
ITEM_CONST_REF |
CONST |
Item reference; object on the stack, constant key |
|
ITEM_CONST_STORE |
CONST |
Set item; object on the stack, constant key |
|
ITEM_CONST_STORE_CONST |
EXTRA |
Set item to a constant; object on the stack, constant key |
|
ITEM_CONST_STORE_VAR |
EXTRA |
Set item; object on the stack, constant key, value by name |
|
ITEM_CONST_STORE_FAST |
EXTRA |
Set item; object on the stack, constant key, value from a fast slot |
|
ITEM_CONST_INPLACE |
EXTRA |
Reduce item in place; object on the stack, constant key |
|
ITEM_CONST_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object on the stack, constant key |
|
ITEM_VAR |
VAR |
Get item; object on the stack, key by name |
|
ITEM_VAR_CLEAR |
VAR |
Delete item; object on the stack, key by name |
|
ITEM_VAR_TAKE |
VAR |
Take item; object on the stack, key by name |
|
ITEM_VAR_REF |
VAR |
Item reference; object on the stack, key by name |
|
ITEM_VAR_STORE |
VAR |
Set item; object on the stack, key by name |
|
ITEM_VAR_STORE_CONST |
EXTRA |
Set item to a constant; object on the stack, key by name |
|
ITEM_VAR_STORE_VAR |
EXTRA |
Set item; object on the stack, key by name, value by name |
|
ITEM_VAR_INPLACE |
EXTRA |
Reduce item in place; object on the stack, key by name |
|
ITEM_VAR_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object on the stack, key by name |
|
ITEM_FAST |
FASTVAR |
Get item; object on the stack, key from a fast slot |
|
ITEM_FAST_CLEAR |
FASTVAR |
Delete item; object on the stack, key from a fast slot |
|
ITEM_FAST_TAKE |
FASTVAR |
Take item; object on the stack, key from a fast slot |
|
ITEM_FAST_REF |
FASTVAR |
Item reference; object on the stack, key from a fast slot |
|
ITEM_FAST_STORE |
FASTVAR |
Set item; object on the stack, key from a fast slot |
|
ITEM_FAST_STORE_CONST |
EXTRA |
Set item to a constant; object on the stack, key from a fast slot |
|
ITEM_FAST_STORE_FAST |
EXTRA |
Set item; object on the stack, key from a fast slot, value from a fast slot |
|
ITEM_FAST_INPLACE |
EXTRA |
Reduce item in place; object on the stack, key from a fast slot |
|
ITEM_FAST_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object on the stack, key from a fast slot |
|
VAR_ITEM |
VAR |
Get item; object by name, key on the stack |
|
VAR_ITEM_CLEAR |
VAR |
Delete item; object by name, key on the stack |
|
VAR_ITEM_TAKE |
VAR |
Take item; object by name, key on the stack |
|
VAR_ITEM_REF |
VAR |
Item reference; object by name, key on the stack |
|
VAR_ITEM_STORE |
VAR |
Set item; object by name, key on the stack |
|
VAR_ITEM_STORE_CONST |
EXTRA |
Set item to a constant; object by name, key on the stack |
|
VAR_ITEM_STORE_VAR |
EXTRA |
Set item; object by name, key on the stack, value by name |
|
VAR_ITEM_INPLACE |
EXTRA |
Reduce item in place; object by name, key on the stack |
|
VAR_ITEM_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object by name, key on the stack |
|
VAR_ITEM_CONST |
EXTRA |
Get item; object by name, constant key |
|
VAR_ITEM_CONST_CLEAR |
EXTRA |
Delete item; object by name, constant key |
|
VAR_ITEM_CONST_TAKE |
EXTRA |
Take item; object by name, constant key |
|
VAR_ITEM_CONST_REF |
EXTRA |
Item reference; object by name, constant key |
|
VAR_ITEM_CONST_STORE |
EXTRA |
Set item; object by name, constant key |
|
VAR_ITEM_CONST_STORE_CONST |
EXTRA |
Set item to a constant; object by name, constant key |
|
VAR_ITEM_CONST_STORE_VAR |
EXTRA |
Set item; object by name, constant key, value by name |
|
VAR_ITEM_CONST_INPLACE |
EXTRA |
Reduce item in place; object by name, constant key |
|
VAR_ITEM_CONST_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object by name, constant key |
|
VAR_ITEM_VAR |
EXTRA |
Get item; object by name, key by name |
|
VAR_ITEM_VAR_CLEAR |
EXTRA |
Delete item; object by name, key by name |
|
VAR_ITEM_VAR_TAKE |
EXTRA |
Take item; object by name, key by name |
|
VAR_ITEM_VAR_REF |
EXTRA |
Item reference; object by name, key by name |
|
VAR_ITEM_VAR_STORE |
EXTRA |
Set item; object by name, key by name |
|
VAR_ITEM_VAR_STORE_CONST |
EXTRA |
Set item to a constant; object by name, key by name |
|
VAR_ITEM_VAR_STORE_VAR |
EXTRA |
Set item; object by name, key by name, value by name |
|
VAR_ITEM_VAR_INPLACE |
EXTRA |
Reduce item in place; object by name, key by name |
|
VAR_ITEM_VAR_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object by name, key by name |
|
FAST_ITEM |
FASTVAR |
Get item; object from a fast slot, key on the stack |
|
FAST_ITEM_CLEAR |
FASTVAR |
Delete item; object from a fast slot, key on the stack |
|
FAST_ITEM_TAKE |
FASTVAR |
Take item; object from a fast slot, key on the stack |
|
FAST_ITEM_REF |
FASTVAR |
Item reference; object from a fast slot, key on the stack |
|
FAST_ITEM_STORE |
FASTVAR |
Set item; object from a fast slot, key on the stack |
|
FAST_ITEM_STORE_CONST |
EXTRA |
Set item to a constant; object from a fast slot, key on the stack |
|
FAST_ITEM_STORE_FAST |
EXTRA |
Set item; object from a fast slot, key on the stack, value from a fast slot |
|
FAST_ITEM_INPLACE |
EXTRA |
Reduce item in place; object from a fast slot, key on the stack |
|
FAST_ITEM_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object from a fast slot, key on the stack |
|
FAST_ITEM_CONST |
EXTRA |
Get item; object from a fast slot, constant key |
|
FAST_ITEM_CONST_CLEAR |
EXTRA |
Delete item; object from a fast slot, constant key |
|
FAST_ITEM_CONST_TAKE |
EXTRA |
Take item; object from a fast slot, constant key |
|
FAST_ITEM_CONST_REF |
EXTRA |
Item reference; object from a fast slot, constant key |
|
FAST_ITEM_CONST_STORE |
EXTRA |
Set item; object from a fast slot, constant key |
|
FAST_ITEM_CONST_STORE_CONST |
EXTRA |
Set item to a constant; object from a fast slot, constant key |
|
FAST_ITEM_CONST_STORE_FAST |
EXTRA |
Set item; object from a fast slot, constant key, value from a fast slot |
|
FAST_ITEM_CONST_INPLACE |
EXTRA |
Reduce item in place; object from a fast slot, constant key |
|
FAST_ITEM_CONST_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object from a fast slot, constant key |
|
FAST_ITEM_FAST |
EXTRA |
Get item; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_CLEAR |
EXTRA |
Delete item; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_TAKE |
EXTRA |
Take item; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_REF |
EXTRA |
Item reference; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_STORE |
EXTRA |
Set item; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_STORE_CONST |
EXTRA |
Set item to a constant; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_STORE_FAST |
EXTRA |
Set item; object from a fast slot, key from a fast slot, value from a fast slot |
|
FAST_ITEM_FAST_INPLACE |
EXTRA |
Reduce item in place; object from a fast slot, key from a fast slot |
|
FAST_ITEM_FAST_INPLACE_CONST |
EXTRA |
Reduce item in place by a constant; object from a fast slot, key from a fast slot |
|
DEREF |
NOARG |
Pop Ref, call ref.deref(), push result |
|
BUILD_ARGS |
COUNT |
Pop N elements and push a tuple of them |
|
BUILD_FUNCTION |
EXTRA |
Build function from spec, with keyword defaults and annotations from names tuples |
|
BUILD_KWDS |
PAIR_COUNT |
Pop 2N elements as key/value pairs and push a dict |
|
BUILD_KWDS_NAMES |
CONST |
Pop N values, pair them with the pooled names tuple, push a dict |
|
BUILD_LIST |
COUNT |
Pop N elements into a new list and push it |
|
BUILD_LIST_CONST |
CONST |
Push a fresh list built from the pooled sequence |
|
VAR_LIST_APPEND |
VAR |
Append TOS to the list bound to the named variable, in place |
|
FAST_LIST_APPEND |
FASTVAR |
Fast-slot form of VAR_LIST_APPEND |
|
BUILD_LIST_APPEND |
COUNT |
Append the top N values to the list beneath them, in place; leave the list |
|
BUILD_LIST_APPEND_CONST |
CONST |
Append the pooled value to the TOS list, in place |
|
BUILD_LIST_EXTEND |
NOARG |
Extend the list in place from the TOS iterable; leave the list |
|
BUILD_LIST_EXTEND_CONST |
CONST |
Extend the TOS list in place from the pooled sequence |
|
COMBINE_ARGS |
COUNT |
Concatenate the M sequences into a single tuple |
|
COMBINE_KWDS |
COUNT |
Merge the M dicts, later entries winning on a key clash |
|
CALL |
COUNT |
Call with N positional args |
|
CALL_NAMES |
COUNT |
Call with keyword names on stack |
|
CALL_STAR |
STAR |
Call with *args and/or **kwargs |
|
CALL_VAR |
EXTRA |
Call callable from namespace by name |
|
CALL_FAST |
EXTRA |
Call callable from fast local slot |
|
CALL_VAR_NAMES |
EXTRA |
Call by name with keyword args |
|
CALL_FAST_NAMES |
EXTRA |
Call from fast slot with keyword args |
|
CALL_VAR_STAR |
EXTRA |
Call by name with *args/**kwargs |
|
CALL_FAST_STAR |
EXTRA |
Call from fast slot with *args/**kwargs |
|
CALL_ATTR |
EXTRA |
Call obj.name with N positional args |
|
CALL_ATTR_NAMES |
EXTRA |
Call obj.name with positional + keyword args |
|
CALL_FAST_ATTR |
EXTRA |
Call obj.name with N positional args; obj from fast slot |
|
CALL_VAR_ATTR |
EXTRA |
Call obj.name with N positional args; obj from VAR |
|
CALL_FAST_ATTR_NAMES |
EXTRA |
Call obj.name with positional + keyword args; obj from fast slot |
|
CALL_VAR_ATTR_NAMES |
EXTRA |
Call obj.name with positional + keyword args; obj from VAR |
|
CALL_ATTR_STAR |
EXTRA |
Call obj.name with *args/**kwargs |
|
CALL_VAR_ATTR_STAR |
EXTRA |
Call obj.name with *args/**kwargs; obj from VAR |
|
CALL_FAST_ATTR_STAR |
EXTRA |
Call obj.name with *args/**kwargs; obj from fast slot |
|
TAIL_CALL |
COUNT |
Tail call (replace frame) |
|
TAIL_CALL_NAMES |
COUNT |
Tail call with keyword names |
|
TAIL_CALL_STAR |
STAR |
Tail call with *args and/or **kwargs |
|
TAIL_CALL_ATTR |
EXTRA |
Tail call obj.name with N positional args |
|
TAIL_CALL_ATTR_NAMES |
EXTRA |
Tail call obj.name with positional + keyword args |
|
TAIL_CALL_ATTR_STAR |
EXTRA |
Tail call obj.name with *args/**kwargs |
|
TAIL_CALL_VAR |
EXTRA |
Tail call callable from namespace by name |
|
TAIL_CALL_VAR_NAMES |
EXTRA |
Tail call by name with keyword args |
|
TAIL_CALL_VAR_STAR |
EXTRA |
Tail call by name with *args/**kwargs |
|
TAIL_CALL_VAR_ATTR |
EXTRA |
Tail call obj.name; obj from VAR |
|
TAIL_CALL_VAR_ATTR_NAMES |
EXTRA |
Tail call obj.name with keyword args; obj from VAR |
|
TAIL_CALL_VAR_ATTR_STAR |
EXTRA |
Tail call obj.name with *args/**kwargs; obj from VAR |
|
TAIL_CALL_FAST |
EXTRA |
Tail call callable from fast local slot |
|
TAIL_CALL_FAST_NAMES |
EXTRA |
Tail call from fast slot with keyword args |
|
TAIL_CALL_FAST_STAR |
EXTRA |
Tail call from fast slot with *args/**kwargs |
|
TAIL_CALL_FAST_ATTR |
EXTRA |
Tail call obj.name; obj from fast slot |
|
TAIL_CALL_FAST_ATTR_NAMES |
EXTRA |
Tail call obj.name with keyword args; obj from fast slot |
|
TAIL_CALL_FAST_ATTR_STAR |
EXTRA |
Tail call obj.name with *args/**kwargs; obj from fast slot |
|
PUSH_FOREACH |
NOARG |
Push foreach region; break target from extent table |
|
PUSH_LOOP |
NOARG |
Push loop region; break target from extent table |
|
POP_FOREACH |
NOARG |
Pop foreach region; push loop result |
|
POP_LOOP |
NOARG |
Pop loop region; push loop result |
|
CLEAR_LOOP |
NOARG |
Disable top LOOP region (before POP_LOOP) |
|
CLEAR_FOREACH |
NOARG |
Disable top FOREACH region (before POP_FOREACH) |
|
PUSH_NS |
EXTRA |
Push namespace scope (nspec + names in extra row) |
|
POP_NS |
NOARG |
Pop the NS scope; the revealed node’s namespace becomes active and leftover values are delivered to its segment |
|
PUSH_COLLECT |
CONST |
Push collector namespace scope |
|
POP_COLLECT |
NOARG |
Pop collect scope, push ns |
|
BUILD_CLASS |
NOARG |
Consume pos+ns, call metaclass |
|
PUSH_TRY |
LABEL |
Push try region |
|
PUSH_FINALLY |
LABEL |
Push finally region and its segment |
|
CLEAR_TRY |
NOARG |
Disable the top TRY region on non-local exit; POP_TRY still drops the segment |
|
CLEAR_FINALLY |
NOARG |
Disable the top FINALLY region on non-local exit; POP_FINALLY still runs at the target |
|
POP_TRY |
NOARG |
Promote the one value on the try segment, drop the segment, pop the region |
|
POP_FINALLY |
NOARG |
As POP_TRY, for the finally segment |
|
PUSH_WITH |
CONST |
Pop the manager, call enter, bind the result, push a single-shot WITH node and a fresh segment |
|
POP_WITH |
NOARG |
Call exit, pop the owned segment and the node, push None |
|
PUSH_DYN_WITH |
CONST |
As PUSH_WITH, with a multi-shot node that takes part in continuation transfer plans |
|
POP_DYN_WITH |
NOARG |
As POP_WITH, for the multi-shot node |
|
OBJECT_COMPARE |
CMPCOUNT |
Chain-compare N stack values under the packed selector and push the result |
|
OBJECT_COMPARE_VAR |
EXTRA |
The ternary bounds idiom with the middle operand resolved by name |
|
OBJECT_COMPARE_FAST |
EXTRA |
The ternary bounds idiom with the middle operand from a fast slot |
|
OBJECT_OPERAND |
OPCOUNT |
Reduce the N operands left to right under the operator |
|
OBJECT_OPERAND_VAR |
EXTRA |
The stack top under the operator with a named right operand |
|
OBJECT_OPERAND_FAST |
EXTRA |
The stack top under the operator with a fast-slot right operand |
|
VAR_OPERAND_VAR |
EXTRA |
Two named operands under the operator, the result pushed |
|
FAST_OPERAND_FAST |
EXTRA |
Two fast-slot operands under the operator, the result pushed |
|
OBJECT_INPLACE |
OPCOUNT |
In-place reduce the N operands left to right, through the |
|
OBJECT_BIT_INVERT |
NOARG |
Pop TOS, push its bitwise inverse |
|
OBJECT_DIR |
NOARG |
Pop TOS, push |
|
OBJECT_DIVMOD |
COUNT |
Pop right then left, push |
|
OBJECT_ITER |
NOARG |
Acquire an iterator over either protocol; a Koskari async generator passes through as itself |
|
OBJECT_LEN |
NOARG |
Pop TOS, push |
|
OBJECT_NOT |
NOARG |
Pop TOS, push its logical negation |
|
OBJECT_REPR |
NOARG |
Pop TOS, push |
|
OBJECT_STR |
COUNT |
Build a string from the top N values (f-string assembly) |
|
OBJECT_FORMAT |
COUNT |
Format the object; arg 2 takes the rules from the stack, arg 1 uses none |
|
OBJECT_FORMAT_CONST |
CONST |
Format the object with format rules from the pool |
|
OBJECT_TRUTH |
NOARG |
Pop TOS, push its truth value |
|
OBJECT_TYPE |
NOARG |
Pop TOS, push |
|
OBJECT_VARS |
NOARG |
Pop TOS, push its |
|
PUSH_PROMPT |
CONST |
Push prompt (delimited cont.) |
|
PUSH_SHIFT |
CONST |
Capture continuation, enter shift block |
|
POP_SHIFT |
NOARG |
Return from shift block without invoking k |
|
POP_PROMPT |
NOARG |
Pop prompt |
|
PUSH_CC |
NOARG |
Push an undelimited continuation block onto the dynamic chain |
|
CAPTURE_CC |
COUNT |
Capture the CC extent’s continuation and push it; 1 sets the callee on TOS aside for the capture |
|
POP_CC |
NOARG |
Pop the CC block; also the landing site when a captured continuation is invoked |
|
PUSH_WIND |
COUNT |
Pop the before (and after) thunks, push the wind extent, run before |
|
POP_WIND |
NOARG |
Pop the body result and the wind node, run the after thunk, deliver the result |
|
PUSH_PARAM |
CONST |
Pop N values, bind them to the pooled names, enter the parameterize extent |
|
POP_PARAM |
NOARG |
Pop the param extent and restore the cells it displaced |
|
PARAM |
EXTRA |
Read a parameter by name; count 1 supplies a stacked default, count 0 raises NameError on a miss |
|
PARAM_CONST |
EXTRA |
Read a parameter by name with a pooled default; never raises for an unbound name |
|
THEEND |
NOARG |
Unreachable; no runtime |
Completeness: Every member of the KosOpCode enum in koskari/lib/opcodes.incl has a dedicated ### KOS_OP_* heading in this document (some sections group related opcodes under one narrative first, then list each name). Search for ### KOS_OP_ to enumerate. Opcodes not listed in opcodes.incl are
not documented here until they are added to the enum.
3. No-op and compile-time
KOS_OP_NOOP
Style: NOARG. Argument unused.
Stack: No change.
Invariants: None beyond global.
Behavior: Advance PC only; no effect.
Example: NOOP in a short sequence (e.g. after label resolution).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (42) |
stack: […, 42] |
1 |
NOOP |
0 |
0 |
no effect; advance PC |
2 |
RETURN |
1 |
1 |
KOS_OP_LABEL
Style: COMPILE. Compile-time only.
Stack: No change.
Invariants: Not present in final bytecode after normal finalize; or executed as no-op if retained.
Behavior: Jump target placeholder. Finalize resolves branch targets to the LABEL’s pc, then strips the LABEL instruction (branch args are adjusted to point at the next instruction). If a LABEL is retained, it advances PC only (safety net).
Compiler form: Pre-compile arg = string (label name). Branches refer to this name; finalize resolves names to pcs and strips LABEL. Post-compile: normally omitted; if retained, arg is 0 or unused.
Pre-compile example: List of (opcode, arg) pairs. The label name "done" is used by JUMP; finalize resolves it and then strips the LABEL.
["JUMP", "done"],
["CONST", 99],
["LABEL", "done"],
["RETURN", 1],
Post-compile (normal): LABEL is stripped. JUMP’s target was the LABEL at index 2; after stripping, that target becomes index 1 (the next instruction). Constant 99 is in the pool at index 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
JUMP |
1 |
1 (-> 1) |
branch to “done” (was LABEL at 2; after strip, target is 1) |
1 |
CONST |
0 |
0 (99) |
dead code; pool 0 = 99 |
2 |
RETURN |
1 |
1 |
(was index 3 before strip) |
Post-compile (if LABEL retained): Safety-net case only. If the LABEL were not stripped, it would appear as below and execute as a no-op.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
JUMP |
2 |
2 (-> 2) |
branch to label |
1 |
CONST |
0 |
0 (99) |
dead code |
2 |
LABEL |
0 |
– |
target “done”; no-op if executed |
3 |
RETURN |
1 |
1 |
KOS_OP_POSITION
Style: COMPILE. Compile-time only.
Stack: No change.
Invariants: Position is recorded in the code object’s position table during finalize. The POSITION instruction itself is normally omitted from the bytecode.
Behavior: Source position marker. Finalize records the position (line, col) in the position table and strips the POSITION instruction. If a POSITION is retained, it advances PC only (safety net).
Compiler form: Pre-compile arg may be (line, col) or a position token; finalize records position in the position table and strips POSITION. Post-compile: normally omitted; if retained, arg typically 0 or unused.
Example: Normally POSITION is stripped; position is stored in the position table only, so the bytecode would be: 0 CONST, 1 RETURN. If POSITION were retained (safety net), it would look like:
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
POSITION |
0 |
– |
line 1, col 0 (in position table); no-op if executed |
1 |
CONST |
0 |
0 (1) |
stack: […, 1] |
2 |
RETURN |
1 |
1 |
4. Stack
KOS_OP_DUP
Style: COUNT. Arg = number of elements to duplicate.
Stack:
[..., a_1, ..., a_n] -> [..., a_1, ..., a_n, a_1, ..., a_n](topargelements duplicated).Invariants: Stack must have at least
argelements.
Example: DUP 1: duplicate TOS (e.g. for use in two branches).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (10) |
stack: […, 10] |
1 |
DUP |
1 |
1 |
stack: […, 10, 10] |
2 |
RETURN |
1 |
1 |
KOS_OP_POP
Style: COUNT. Arg = number of elements to pop.
Stack:
[..., a_1, ..., a_n] -> [...](popargelements).Invariants: Stack must have at least
argelements.
Example: POP 1: discard TOS.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (1) |
stack: […, 1] |
1 |
CONST |
1 |
1 (2) |
stack: […, 1, 2] |
2 |
POP |
1 |
1 |
stack: […, 1] |
3 |
RETURN |
1 |
1 |
KOS_OP_UNPACK
Style: COUNT. Arg =
n(number of values to push).Stack:
[..., raw] -> [..., v_{n-1}, ..., v_1, v_0]wherev_iis thei-th element of the realized sequence and TOS = v_0 = seq[0] (so the first binding in source order can useVAR_STORE/FAST_STOREon TOS first). A tuple or list is read in place; any other iterable is pulled fornitems plus one, so an over-long iterable is refused at its extra item and never drained.Invariants:
n >= 0. Forn == 0, TOS must be an empty iterable.Errors:
ValueErrorif the count is notn;TypeErrorwhen TOS is not iterable.Compiler form: Pre-compile / post-compile arg =
n(uint16).
Example: Unpack (1, 2, 3) so TOS is 1, then return three values (stack
bottom to top matches push order).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ((1,2,3)) |
stack: […, (1,2,3)] |
1 |
UNPACK |
3 |
3 |
stack: […, 3, 2, 1]; TOS = 1 |
2 |
RETURN |
3 |
3 |
KOS_OP_UNPACK_STAR
Style: EXTRA (
COUNT,COUNT,NOARG,NOARG). Instruction arg = index into the code object’s extra table; that row hasa0 = left,a1 = right(both non-negative counts).Semantics: Pop TOS,
PySequence_List(raw). Requireleft + right > 0andlen(seq) >= left + right. LetL = len(seq). The middle slice isseq[left : L - right](inclusive start, exclusive end), materialized as a tuple (new reference). Pushes are ordered so that after all pushes, TOS is the first prefix elementseq[0](whenleft > 0):Suffix scalars: indices
L-1, L-2, ..., L-right(each viaKosStack_PushRef).Middle: one value – the tuple – via
KosStack_PUSH(stolen reference fromPySequence_Tuple).Prefix scalars: indices
left-1, ..., 0(each viaPushRef).
Stack (TOS right):
[..., raw] -> [..., seq[L-1], ..., seq[L-right], middle, seq[left-1], ..., seq[0]]when all parts are non-empty; adjust whenleftorrightis zero (no prefix or suffix pushes for that side).Invariants: Extra row matches schema;
left + rightfits in uint16; realized value must be a valid sequence forPySequence_List/ slicing.Errors:
ValueErrorifleft + right == 0orlen(seq) < left + right.Compiler form: Pre-compile extra operand is a 4-tuple
(left, right, 0, 0);NOARGslots are ignored by the assembler. Same pattern as otherEXTRAopcodes (see section 1.7).
Example: left=2, right=1, seq (1,2,3,4): suffix [4], middle
(3,), prefix 2, 1 with TOS 1.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ((1,2,3,4)) |
|
1 |
UNPACK_STAR |
0 |
0 (2, 1, …) |
extra row: left=2, right=1 |
2 |
RETURN |
4 |
4 |
stack bottom..top: 4, (3,), 2, 1 |
KOS_OP_UNPACK_VAR
Style: EXTRA (
VAR,VAR,NOARG,NOARG). Row:a0,a1= constant pool indices of the two names (strings).Stack:
[..., raw] -> [...]. No values pushed; STORE semantics only (same asVAR_STORE/KosNamespace_Storethroughframe_ns_store):seq[0]into the first name,seq[1]into the second. Pop TOS,PySequence_List, requirelen == 2, then store; release the temporary list.Invariants: Both names must already be bound in the frame namespace (see section 1.9 STORE vs BIND).
Errors:
ValueErrorif length != 2.Compiler form: Pre-compile extra tuple
(name0, name1, 0, 0); names intern to cpool like otherVARextra fields.
KOS_OP_UNPACK_FAST
Style: EXTRA (
FASTVAR,FASTVAR,NOARG,NOARG). Row:a0,a1= fast local slot indices.Stack:
[..., raw] -> [...]. Pop TOS,PySequence_List, requirelen == 2, thenKosNamespace_FastStorefor slota0withseq[0]and slota1withseq[1](same ownership rules asFAST_STORE: namespace increments ref as needed).Invariants: Frame namespace supports fast locals; both indices in range (same as
FAST_STORE).Errors:
ValueErrorif length != 2;RuntimeError/NameErrorif fast namespace invalid or index out of bounds.Compiler form: Pre-compile extra tuple
(slot0, slot1, 0, 0)with integer slot indices.
5. Constants
KOS_OP_CONST
Style: CONST. Arg = constant pool index (post-compile).
Stack:
[...] -> [..., c]wherec = cpool[arg].Invariants:
arg < cpool_len.Compiler form: Pre-compile arg = literal value (e.g.
CONST "hello",CONST 42). Finalize accumulates values into the constant pool and rewrites arg to the pool index.
Example: Load constant at index 0 (value 42). Pool: 0 = 42.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (42) |
stack: […, 42] |
1 |
RETURN |
1 |
1 |
KOS_OP_CONST2
Style: EXTRA (CONST, CONST, NOARG, NOARG). Row = two constant pool indices (post-compile).
Stack:
[...] -> [..., a, b]. Push the two constants in row order. A constant is a borrowed pool reference, so a failed push leaves nothing to release.Invariants: Indices in the constant pool.
Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs(the trailing pack phase), which combines a run of consecutive bare CONST loads: quads, then one triple or one pair, then a bare load for a remainder of one. Constant folding runs earlier, so only loads the folder kept apart, such as a call’s arguments, pack.Implementation:
koskari/lib/opcode/CONST2.cCovered by:
tests/compile/test_combine_const.py,tests/reproducers/test_var_pack.py
Example: Load constants a, b. Pool: 0 = a, 1 = b.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST2 |
0 |
(0 (a), 1 (b), 0, 0) |
stack: […, a, b] |
1 |
RETURN |
1 |
1 |
KOS_OP_CONST3
Style: EXTRA (CONST, CONST, CONST, NOARG). Row = three constant pool indices (post-compile).
Stack:
[...] -> [..., a, b, c]. Push the three constants in row order. A constant is a borrowed pool reference, so a failed push leaves nothing to release.Invariants: Indices in the constant pool.
Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs(the trailing pack phase), which combines a run of consecutive bare CONST loads: quads, then one triple or one pair, then a bare load for a remainder of one. Constant folding runs earlier, so only loads the folder kept apart, such as a call’s arguments, pack.Implementation:
koskari/lib/opcode/CONST3.cCovered by:
tests/compile/test_combine_const.py,tests/reproducers/test_var_pack.py
Example: Load constants a, b, c. Pool: 0 = a, 1 = b, 2 = c.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST3 |
0 |
(0 (a), 1 (b), 2 (c), 0) |
stack: […, a, b, c] |
1 |
RETURN |
1 |
1 |
KOS_OP_CONST4
Style: EXTRA (CONST, CONST, CONST, CONST). Row = four constant pool indices (post-compile).
Stack:
[...] -> [..., a, b, c, d]. Push the four constants in row order. A constant is a borrowed pool reference, so a failed push leaves nothing to release.Invariants: Indices in the constant pool.
Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs(the trailing pack phase), which combines a run of consecutive bare CONST loads: quads, then one triple or one pair, then a bare load for a remainder of one. Constant folding runs earlier, so only loads the folder kept apart, such as a call’s arguments, pack.Implementation:
koskari/lib/opcode/CONST4.cCovered by:
tests/compile/test_combine_const.py,tests/reproducers/test_var_pack.py
Example: Load constants a, b, c, d. Pool: 0 = a, 1 = b, 2 = c, 3 = d.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST4 |
0 |
(0 (a), 1 (b), 2 (c), 3 (d)) |
stack: […, a, b, c, d] |
1 |
RETURN |
1 |
1 |
5.1 Pair construction and access
KOS_OP_CAR
Style: COUNT. Arg = repeat count: apply car that many times to the stack top (each step pops one pair and pushes its car).
Invariants:
n>= 1.n<= 0 (including CAR 0) is invalid: RuntimeError (CAR invoked with invalid argument count: ...); the stack is not modified because the handler returns before popping TOS.Stack: With valid
n>= 1, same effect asnchained CAR 1 instructions (one stack pop of the initial value, local walk, one push). If any intermediate value is not a pair or is nil, TypeError (message includes step index and type /nil).
KOS_OP_CDR
Style: COUNT. Arg = repeat count: apply cdr that many times to the stack top (each step pops one pair and pushes its cdr).
Invariants:
n>= 1.n<= 0 (including CDR 0) is invalid: RuntimeError (CDR invoked with invalid argument count: ...); the stack is not modified because the handler returns before popping TOS.Stack: With valid
n>= 1, same effect asnchained CDR 1 instructions (one stack pop, local walk, one push). If any intermediate value is not a pair or is nil, TypeError (message includes step index and type /nil).
KOS_OP_CONS
Style: COUNT. Arg = number of values on stack (bottom = first element, top = tail).
Stack:
[..., e_0, ..., e_{count-1}] -> [..., result]where result = (e_0 . (e_1 . … (e_{count-1}) …)). Implemented via KosStack_TailPtr, KosPair_ConsFromPtr, KosStack_Drop, then push result. count 0 -> push nil (INCREF).
KOS_OP_PROPER
Style: COUNT. Arg = number of element values on stack.
Stack:
[..., e_0, ..., e_{count-1}] -> [..., result]where result is the proper list(e_0 e_1 ... e_{count-1}). nil is implicitly appended as the tail. count 0 -> push nil directly.Invariants: Each
e_imay be any Python object; none need be a pair.Use-case: Emitted by the quasiquote compiler for segments of non-splice elements. Equivalent to CONS with an extra
CONST nilon the stack, but more compact: saves one instruction per list.
Example: Build the proper list (a b c) from three constants.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (sym a) |
stack: […, a] |
1 |
CONST |
1 |
1 (sym b) |
stack: […, a, b] |
2 |
CONST |
2 |
2 (sym c) |
stack: […, a, b, c] |
3 |
PROPER |
3 |
3 |
stack: […, (a b c)] |
KOS_OP_BRACKET_CONS
Style: COUNT. Arg = number of values on stack (bottom = first element, top = tail).
Stack:
[..., e_0, ..., e_{count-1}] -> [..., result]where result is the bracket pair chain[e_0 . [e_1 . ... [e_{count-1}] ...]]. The twin of CONS over bracket pairs, built with KosBracketPair_ConsFromPtr. count 0 -> push bracket-nil.Use-case: Emitted by
compile/bracket-consand by the quasiquote compiler for a[ ]form with an explicit tail.
KOS_OP_BRACKET_PROPER
Style: COUNT. Arg = number of element values on stack.
Stack:
[..., e_0, ..., e_{count-1}] -> [..., result]where result is the proper bracket list[e_0 e_1 ... e_{count-1}]. bracket-nil is implicitly appended as the tail. count 0 -> push bracket-nil directly.Use-case: Emitted by
compile/bracket-properand by the quasiquote compiler for the segments of a[ ]form; the twin of PROPER.
KOS_OP_PAIR_SPLICE
Style: EXTRA (COUNT, COUNT). Row = count of stacked values (bottom = first), tail flag (0 or 1).
Stack: tail 0:
[..., seg_0, ..., seg_{count-1}] -> [..., result]where result is the concatenation of all segments as a single proper list. tail 1:[..., seg_0, ..., seg_{count-2}, tail] -> [..., result]where the top value is the tail and the count minus one values below it are the segments; the last cell’s cdr is the tail. Each segment may be: nil (contributes nothing), a pair (proper or improper; its elements are appended), a Python tuple (its elements are appended), or any iterable. count 0 -> push nil.Invariants: All segments must be iterable; non-iterable values raise TypeError. With tail 0 the result is a proper pair list, or nil if all segments are empty. With tail 1 the result ends in the tail, or is the tail itself if all segments are empty. Dotted-pair segments are walked until nil; the implicit nil tail of the last segment is not included.
Use-case: Emitted by the quasiquote compiler when at least one
unquote-splicingsite is present in a( )list; a[ ]list uses BRACKET_SPLICE. Each constant-only segment is folded into a singleCONST tuple(which PAIR_SPLICE accepts natively), reducing instruction count significantly for mostly-literal lists.
Example: Splice a variable list b between constants.
`(a ,@b c) compiles to roughly:
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ((sym a,)) |
segment: tuple |
1 |
VAR |
1 |
1 (b) |
splice value |
2 |
CONST |
2 |
2 ((sym c,)) |
segment: tuple |
3 |
PAIR_SPLICE |
0 |
0 (3, 0) |
stack: […, (a . (b_0 … b_n . (c)))] |
KOS_OP_BRACKET_SPLICE
Style: EXTRA (COUNT, COUNT). Row = count of stacked values (bottom = first), tail flag (0 or 1).
Stack: tail 0:
[..., seg_0, ..., seg_{count-1}] -> [..., result]where result is the concatenation of all segments, with a bracket pair as its leading cell. tail 1:[..., seg_0, ..., seg_{count-2}, tail] -> [..., result]where the top value is the tail and the last cell’s cdr is that tail. The twin of PAIR_SPLICE for bracket lists; segments and the tail flag are accepted as PAIR_SPLICE accepts them. count 0 -> push bracket-nil.Invariants: Only the leading cell is a bracket pair; the rest of the spine is plain pairs ending in nil, or in the tail with tail 1. If every segment is empty the result is bracket-nil with tail 0, or the tail itself with tail 1.
Use-case: Emitted by the quasiquote compiler for a
[ ]list holding at least oneunquote-splicingsite. No name is looked up, so a binding of any name leaves the result unchanged.
6. Mode control
KOS_OP_AWAIT
Style: COUNT (stack element count).
Arg:
1– pop TOS (awaitable), dispatch; may returnEVAL_AWAIT(val)or push the resolved value; on resume from a Python awaitable, result is pushed onto the operand stack.0– bare cooperative suspend: no stack pop or push; returnsEVAL_AWAIT(Py_None)(nopy_await_iter);revive_awaitdoes not push the resume value onto the operand stack (e.g. next instruction may beCONST Nonefor(await)).
Example: Await a coroutine; TOS is the awaitable. On resume, result is pushed.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (coro) |
stack: […, awaitable] |
1 |
AWAIT |
1 |
1 |
pop one; suspend; on resume stack: […, value] |
2 |
RETURN |
1 |
1 |
KOS_OP_BREAK
Style: COUNT. Arg = number of stack elements to pop before jumping.
Stack: Pops
argelements; control transfers to break target of innermost LOOP/FOREACH extent.Invariants: Must be inside a LOOP or FOREACH extent.
Example: Inside a loop; pop 0 and jump to extent break_pc (instruction after the matching POP_LOOP or POP_FOREACH).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
BREAK |
0 |
0 |
pop 0, jump to break target (e.g. pc 6) |
… |
… |
… |
… |
|
6 |
POP_LOOP |
0 |
0 |
break target (LOOP extent; use POP_FOREACH for FOREACH) |
KOS_OP_CONTINUE
Style: COUNT. Arg = number of stack elements to pop before jumping.
Stack: Pops
argelements; control transfers to continue target of innermost LOOP/FOREACH extent.Invariants: Must be inside a LOOP or FOREACH extent.
Example: Inside a loop; pop 0 and jump to extent continue_pc (e.g. loop head).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
4 |
CONTINUE |
0 |
0 |
pop 0, jump to continue target (e.g. pc 1) |
… |
… |
… |
… |
KOS_OP_RAISE
Style: COUNT. Arg = number of values to pop (e.g. 1 for exception instance).
Stack: Pops
argvalues; raises with the popped exception.Invariants: Popped value(s) form the exception to raise.
Example: Raise exception from TOS (arg = 1). Pool: 0 = ValueError(“bad”).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (ValueError(…)) |
stack: […, exc] |
1 |
RAISE |
1 |
1 |
pop 1, raise exc; stack unwound |
KOS_OP_RETURN
Style: COUNT. Arg = number of values to package as the return value:
0returnsNone,1returns the single popped value, andN > 1popsNvalues and returns them as a tuple.Stack: Pops the return value(s) per
arg. The returning frame’s dynamic extent unwinds, finally blocks and wind thunks included, and the frame is popped. The value goes where the frame’s parent expects it: pushed onto a calling Koskari frame, delivered to the iterator or native handler driving the frame, or handed back to the host when the frame is the outermost one or a generator’s. A return across a delimited continuation boundary delivers to that boundary.Invariants: See execution-invariants: in-loop flattening for RETURN.
See also: compile/return.
Example: Return TOS (arg = 1). Pool: 0 = 42.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (42) |
stack: […, 42] |
1 |
RETURN |
1 |
1 |
return 42 to the caller |
KOS_OP_YIELD
Style: COUNT. Arg = number of values to package as the yielded value:
0yieldsNone,1yields the single popped value, andN > 1popsNvalues and yields them as a tuple.Stack: Pops the yielded value(s). Sets
KOS_CODE_YIELDSon the code object. The handler freezes the running generator’s span of the dynamic chain into its generator node. A flattened generator, one consumed inside the same evaluator, then hands the value to the consuming frame (a for-each step, a next request, or a yield-from waiting on it) and continues in that frame without stopping the evaluator. A generator run from outside stops the evaluator with the yielded value.Invariants: Code is treated as async generator when YIELDS flag set.
See also: compile/yield;
koskari/lib/opcode/YIELD.c.
Example: Yield TOS (arg = 1). Pool: 0 = 100.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (100) |
stack: […, 100] |
1 |
YIELD |
1 |
1 |
yield 100; on resume continue |
KOS_OP_RETURN_CONST
Style: CONST. Arg = pool index of the constant to return.
Stack:
[...] -> [...](no stack effect). Returns the constant exactly asKOS_OP_RETURN1 returns a popped value: the same plain, region and resume deliveries, else the RETURN signal to the trampoline.Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhenKOS_OP_RETURN1 is fed by a bareKOS_OP_CONST; aNoneconstant takesKOS_OP_RETURN0 in the squish pass instead.Implementation:
koskari/lib/opcode/RETURN_CONST.c
KOS_OP_YIELD_CONST
Style: CONST. Arg = pool index of the constant to yield.
Stack:
[...] -> [...](no stack effect). Yields the constant exactly asKOS_OP_YIELD1 yields a popped value: a flattened generator delivers to its consumer and threads into it, any other returns the YIELD signal. Marks the code as a generator, asKOS_OP_YIELDdoes.Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhenKOS_OP_YIELD1 is fed by a bareKOS_OP_CONST; aNoneconstant takesKOS_OP_YIELD0 in the squish pass instead.Implementation:
koskari/lib/opcode/YIELD_CONST.c
KOS_OP_YIELD_FROM
Style: NOARG.
Stack: Pops TOS, the value to delegate to. Pushes nothing. Each value the delegate produces is yielded out of the enclosing generator as that generator’s own yield. When the delegate is exhausted, execution continues at the next instruction; the delegate’s return value is discarded.
compile/yield-fromemitsCONST Noneafter the opcode so the form has a value.Execution model: Single-opcode delegation primitive (conduit); not loop sugar. Full send/throw/close propagation; async flattening for Python and Koskari async gens. The delegate is held as the frame’s resume state for the whole delegation; every suspension of the delegation is a resume on the generator’s frame, and what arrives at the generator (a sent value, a thrown exception, a close) arrives at that resume.
Delegate kinds (chosen at first entry by normalizing TOS): sync iterator (PyIter_Next); sync generator (send/throw/close); Python async iterator (anext); Python async generator (anext/asend/athrow/aclose); Koskari async generator (driven in-process via koskari_eval). Callables are called once; the return value is classified as above. Fallback:
iter(obj)for sync iteration.Rejected: Coroutines (Koskari or Python). Normalization raises
TypeError: "coroutine object is not async iterable". Delegate results (yielded or final value) are never re-awaited; they are emitted as values only.Invariants: TOS on first entry must be an iterable or async-iterable (or callable returning one).
Implementation: Handler, normalization, the per-kind drive resumes and the delegate’s close on teardown live in
koskari/lib/opcode/YIELD_FROM.c(included intoeval.c). Seekoskari/lib/opcode/README.mdfor the opcode-fragment layout.See also: compile/yield-from
Covered by:
tests/lib/opcode/test_yield_from.py(sync/async delegates, Koskari async gen, send/throw/close, final values, type errors).
Example: Delegate to a sync iterator; each yielded value is emitted as the generator’s own, and nothing is pushed when the iterator exhausts. Pool: 0 = [1, 2, 3].
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ([1,2,3]) |
stack: […, iterable] |
1 |
YIELD_FROM |
0 |
0 |
consume TOS as the delegate; the instruction halts on its resume, which re-yields each element and answers each send, until the delegate ends; stack: […] |
2 |
RETURN |
1 |
1 |
7. Iteration
KOS_OP_ITER_NEXT
Style: LABEL. Arg = else branch pc (post-compile).
Stack: Uses region iterator (PUSH_FOREACH). If next available: push value; else jump to
arg. Auto-await if iterator is async.Invariants: Must be inside a PUSH_FOREACH extent. Jump target
argmust be local.Compiler form: Pre-compile arg = string label (else / exhausted target); post-compile arg = pc.
Example: For-each body: get next from region iterator; if exhausted jump to 6.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ([1,2,3]) |
stack: […, iterable] |
1 |
PUSH_FOREACH |
0 |
0 |
push region; iterator from iterable; break target from extent table |
2 |
ITER_NEXT |
6 |
6 (-> 6) |
next from region; if exhausted -> pc=6. stack: […, val] or jump |
3 |
POP |
1 |
1 |
consume value (body) |
4 |
JUMP |
2 |
2 (-> 2) |
loop back |
5 |
POP_FOREACH |
0 |
0 |
push loop result (None if unset) |
6 |
LABEL |
– |
– |
else (exhausted) |
KOS_OP_ITER_NEXT_STORE_FAST
Style: EXTRA. Fields: FASTVAR (slot), LABEL (else branch pc, post-compile).
Stack: Uses region iterator (PUSH_FOREACH). If next available: store the element into the fast slot, stack unchanged; else jump to the label. Auto-await if the iterator is async: a deferred element is stored into the slot when it arrives.
Invariants: Must be inside a PUSH_FOREACH extent. The label must be local. The slot must be a fast slot of the current frame namespace.
Compiler form: Produced by the processor from
ITER_NEXTfollowed byVAR_STORE, asITER_NEXT_STORE_VAR, then lowered to this opcode when the name has a fast slot. The for-each special’s binding form compiles to it.
Example: For-each body: next from the region iterator into slot 0; if exhausted jump to 5.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ([1,2,3]) |
stack: […, iterable] |
1 |
PUSH_FOREACH |
0 |
0 |
push region; iterator from iterable |
2 |
ITER_NEXT_STORE_FAST |
0 |
(0, -> 5) |
next from region into slot 0; if exhausted -> pc=5. stack unchanged |
3 |
CONTINUE |
0 |
0 |
back to the step |
4 |
POP_FOREACH |
0 |
0 |
push loop result (None if unset) |
5 |
LABEL |
– |
– |
else (exhausted) |
KOS_OP_ITER_NEXT_STORE_VAR
Style: EXTRA. Fields: VAR (name), LABEL (else branch pc, post-compile).
Stack: Uses region iterator (PUSH_FOREACH). If next available: store the element under the name in the current frame namespace, stack unchanged; else jump to the label. Auto-await if the iterator is async: a deferred element is stored under the name when it arrives.
Invariants: Must be inside a PUSH_FOREACH extent. The label must be local.
Compiler form: Produced by the processor from
ITER_NEXTfollowed byVAR_STORE. A name with a fast slot lowers the opcode toITER_NEXT_STORE_FAST; this form remains where the name has none, such as a module-level loop.
Example: Module-level for-each: next from the region iterator into x; if exhausted jump to 5.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ([1,2,3]) |
stack: […, iterable] |
1 |
PUSH_FOREACH |
0 |
0 |
push region; iterator from iterable |
2 |
ITER_NEXT_STORE_VAR |
0 |
(x, -> 5) |
next from region into x; if exhausted -> pc=5. stack unchanged |
3 |
CONTINUE |
0 |
0 |
back to the step |
4 |
POP_FOREACH |
0 |
0 |
push loop result (None if unset) |
5 |
LABEL |
– |
– |
else (exhausted) |
KOS_OP_OBJECT_NEXT
Style: COUNT. Arg = 1 or 2: 1 = TOS is iterator or async iterator (StopIteration raises on exhaustion); 2 = TOS = default, below = iterator or async iterator (StopIteration pushes default).
Stack: Stack-based next from iterator or async iterator. May suspend on async iterator.
Invariants: TOS (or below-TOS for arg=2) must be a sync iterator or an async iterator. A bare iterable (e.g. list, tuple) is not acceptable; use OBJECT_ITER or equivalent to obtain an iterator first. Stack layout per arg (1 or 2 elements as described).
Example (arg=1): TOS = iterator or async iterator; push next or raise StopIteration.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (iter) |
stack: […, iterator or async iterator] |
1 |
OBJECT_NEXT |
1 |
1 |
stack: […, next_val] or raise StopIteration |
Example (arg=2): TOS = default, below = iterator or async iterator; push next or default.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (iter) |
stack: […, iterator or async iterator] |
1 |
CONST |
1 |
1 (99) |
stack: […, iterator or async iterator, default] |
2 |
OBJECT_NEXT |
2 |
2 |
stack: […, next_val] or […, 99] if exhausted |
KOS_OP_VAR_NEXT
Style: EXTRA (VAR, COUNT). Row = iterator name (pool), n (1 or 2).
Stack: n=1:
[...] -> [..., value]; n=2:[..., default] -> [..., value-or-default]. Fused VAR + OBJECT_NEXT: resolve the iterator name and take the next element as OBJECT_NEXT does. A Koskari async generator runs flattened in the same evaluator; an awaited step suspends the frame and completes the instruction when it resumes. 1-arg raises StopIteration on exhaustion; 2-arg delivers the default.Invariants: The fused name resolution runs after the default row (the fusion requires a bare default feeder, so the reorder is unobservable beyond NameError timing).
Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhen OBJECT_NEXT’s iterator feeder is a bare VAR load (the 2-arg form also requires a bare VAR/CONST default). Lowers to FAST_NEXT through the generic schema-drivenconvert_fastpath.Implementation:
koskari/lib/opcode/VAR_NEXT.c(cold handler)Covered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_object_next.py
KOS_OP_FAST_NEXT
Style: EXTRA (FASTVAR, COUNT). Row = iterator slot, n (1 or 2).
Stack: As VAR_NEXT, with the iterator loaded from its fast slot.
Compiler form: Post-compile only: the generic
convert_fastlowering of VAR_NEXT when the iterator name has a fast slot.Implementation:
koskari/lib/opcode/FAST_NEXT.c(cold handler)Covered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_object_next.py
8. Jumps
KOS_OP_JUMP
Style: LABEL. Arg = target pc (post-compile).
Stack: No change.
Invariants: Target must be inside current extent or at its
pop_pc(jump locality).Compiler form: Pre-compile arg = string label name (must match a LABEL in the same compilation unit). Post-compile arg = pc of that LABEL.
Pre-compile example: Same snippet as LABEL; JUMP uses the string "done".
["JUMP", "done"],
["CONST", 99],
["LABEL", "done"],
["RETURN", 1],
Post-compile example: After finalize, LABEL is stripped (see LABEL). JUMP’s target was the LABEL; it becomes the next instruction (index 1). Constant pool: 0 = 99.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
JUMP |
1 |
1 (-> 1) |
pc := 1 (target “done” after LABEL stripped) |
1 |
CONST |
0 |
0 (99) |
dead code |
2 |
RETURN |
1 |
1 |
KOS_OP_JUMP_FALSE
Style: LABEL. Arg = target pc (post-compile).
Stack: Pops one value; if false, jump to
arg; else advance PC.Invariants: Jump locality for target.
Compiler form: Pre-compile arg = string label; post-compile arg = pc.
Example: Jump if TOS is false (e.g. “else” branch). Pool: 0 = False, 1 = 42, 2 = 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (False) |
stack: […, False] |
1 |
JUMP_FALSE |
4 |
4 (-> 4) |
pop TOS; if false -> pc=4 |
2 |
CONST |
1 |
1 (42) |
stack: […, 42] |
3 |
JUMP |
5 |
5 (-> 5) |
|
4 |
LABEL |
– |
– |
else |
5 |
CONST |
2 |
2 (0) |
stack: […, 0] |
6 |
RETURN |
1 |
1 |
KOS_OP_JUMP_TRUE
Style: LABEL. Arg = target pc (post-compile).
Stack: Pops one value; if true, jump to
arg; else advance PC.Invariants: Jump locality for target.
Compiler form: Pre-compile arg = string label; post-compile arg = pc.
Example: Jump if TOS is true (e.g. “then” branch).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (x) |
stack: […, x] |
1 |
JUMP_TRUE |
3 |
3 (-> 3) |
pop TOS; if true -> pc=3 |
2 |
CONST |
0 |
0 (0) |
else path |
3 |
LABEL |
– |
– |
then path |
4 |
RETURN |
1 |
1 |
KOS_OP_JUMP_FALSE_VAR
Style: EXTRA (VAR, LABEL, NOARG, NOARG). Row = name, target pc.
Stack: No stack effect. Read the value the name resolves to in the current frame’s namespace; if false, jump to the target, else advance. Raises
NameErrorwhen the name is unbound.Invariants: Jump locality for target.
Compiler form: Produced by
ByteCodeProcessor.fuse_feedersabsorbing a bareVARload into theJUMP_FALSEit feeds; aCONSTfeeder was folded in the squish. Lowers to JUMP_FALSE_FAST when the name has a fast slot.
Example: (when x ...) with x resolved by name.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
JUMP_FALSE_VAR |
0 |
(v#0 (‘x’), -> 3, 0, 0) |
if x is false -> pc=3 |
1 |
CONST |
1 |
1 (1) |
body |
2 |
JUMP |
4 |
4 (-> 4) |
|
3 |
CONST |
2 |
2 (None) |
|
4 |
RETURN |
1 |
1 |
KOS_OP_JUMP_TRUE_VAR
Style: EXTRA (VAR, LABEL, NOARG, NOARG). Row = name, target pc.
Stack: No stack effect. Read the value the name resolves to in the current frame’s namespace; if true, jump to the target, else advance. Raises
NameErrorwhen the name is unbound.Invariants: Jump locality for target.
Compiler form: Produced by
ByteCodeProcessor.fuse_feedersabsorbing a bareVARload into theJUMP_TRUEit feeds; aCONSTfeeder was folded in the squish. Lowers to JUMP_TRUE_FAST when the name has a fast slot.
KOS_OP_JUMP_FALSE_FAST
Style: EXTRA (FASTVAR, LABEL, NOARG, NOARG). Row = fast slot, target pc.
Stack: No stack effect. Read the fast slot; if false, jump to the target, else advance. Raises
NameErrorwhen the slot is empty.Invariants: Jump locality for target.
Compiler form: Post-compile only: the
convert_fastlowering of JUMP_FALSE_VAR when the name has a fast slot.(if x ...),(when x ...),(while flag ...)and a bare-variable clause of a threadedand/ortest take one dispatch.
Example: (when x ...) with x in fast slot 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
JUMP_FALSE_FAST |
0 |
(fast 0 (“x”), -> 3, 0, 0) |
if x is false -> pc=3 |
1 |
CONST |
0 |
0 (1) |
body |
2 |
JUMP |
4 |
4 (-> 4) |
|
3 |
CONST |
1 |
1 (None) |
|
4 |
RETURN |
1 |
1 |
KOS_OP_JUMP_TRUE_FAST
Style: EXTRA (FASTVAR, LABEL, NOARG, NOARG). Row = fast slot, target pc.
Stack: No stack effect. Read the fast slot; if true, jump to the target, else advance. Raises
NameErrorwhen the slot is empty.Invariants: Jump locality for target.
Compiler form: Post-compile only: the
convert_fastlowering of JUMP_TRUE_VAR when the name has a fast slot.(if (not x) ...)and anorclause of a threaded test over a bare variable take one dispatch.
KOS_OP_NILP
Style: NOARG.
Stack:
[..., x] -> [..., bool]. Pop TOS; pushTruewhen it is an empty-list singleton (nilor bracket-nil), elseFalse.Compiler form:
Compiler.compresslowers NILP followed by JUMP_FALSE into one CHECK_NIL.Implementation:
koskari/lib/opcode/NILP.c
KOS_OP_CHECK_NIL
Style: LABEL. Arg = target pc (post-compile).
Stack:
[..., x] -> [...]. Pop TOS; branch to arg when it is not an empty-list singleton; fall through when it is.Invariants: Jump locality for target. The squashed form of NILP followed by JUMP_FALSE.
Compiler form: Produced by
Compiler.compress; pre-compile arg = string label, post-compile arg = pc.Implementation:
koskari/lib/opcode/CHECK_NIL.c
KOS_OP_JUMP_AND
Style: LABEL. Short-circuit AND: jump if TOS is false.
Stack: Pops one value; if false, push it back and jump to
arg; if true, discard it and advance. Either way TOS is consumed on the fall-through path.Invariants: Jump locality for target.
Compiler form: Pre-compile arg = string label; post-compile arg = pc.
Compiler use-case: compile/and is the canonical consumer
(koskari/compile/specials/conditionals.py). For (and A B C) the
compiler emits one JUMP_AND done after each non-last term; the last term is
compiled without a jump. Because JUMP_AND already discards the value on the
fall-through path, no POP is needed between terms.
eval A
JUMP_AND done ; falsy -> push A back, jump to done
eval B ; A was already discarded on fall-through
JUMP_AND done
eval C ; last term -- value stays on stack
done:
Example: Short-circuit and: if first operand false, jump to “fail”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (True) |
stack: […, a] |
1 |
JUMP_AND |
4 |
4 (-> 4) |
if not a -> pc=4 |
2 |
CONST |
1 |
1 (True) |
stack: […, b] |
3 |
JUMP_AND |
4 |
4 (-> 4) |
if not b -> pc=4 |
4 |
LABEL |
– |
– |
fail (or result) |
KOS_OP_JUMP_OR
Style: LABEL. Short-circuit OR: jump if TOS is true.
Stack: Pops one value; if true, push it back and jump to
arg; if false, discard it and advance. Either way TOS is consumed on the fall-through path.Invariants: Jump locality for target.
Compiler form: Pre-compile arg = string label; post-compile arg = pc.
Compiler use-case: compile/or is the canonical consumer
(koskari/compile/specials/conditionals.py). For (or A B C) the
compiler emits one JUMP_OR done after each non-last term; the last term is
compiled without a jump. Because JUMP_OR already discards the value on the
fall-through path, no POP is needed between terms.
eval A
JUMP_OR done ; truthy -> push A back, jump to done
eval B ; A was already discarded on fall-through
JUMP_OR done
eval C ; last term -- value stays on stack
done:
Example: Short-circuit or: if first operand true, jump to “ok”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (False) |
stack: […, a] |
1 |
JUMP_OR |
4 |
4 (-> 4) |
if a -> pc=4 |
2 |
CONST |
1 |
1 (False) |
stack: […, b] |
3 |
JUMP_OR |
4 |
4 (-> 4) |
if b -> pc=4 |
4 |
LABEL |
– |
– |
ok |
5 |
RETURN |
1 |
1 |
KOS_OP_JUMP_AND_VAR
Style: EXTRA (VAR, LABEL, NOARG, NOARG). Row = name, target pc.
Stack:
[...] -> [..., x]on the jump,[...] -> [...]on the fall-through. Read the value the name resolves to in the current frame’s namespace; if false, push it and jump to the target; if true, advance with nothing pushed. RaisesNameErrorwhen the name is unbound.Invariants: Jump locality for target.
Compiler form: Produced by
ByteCodeProcessor.fuse_feedersabsorbing a bareVARload into theJUMP_ANDit feeds. Lowers to JUMP_AND_FAST when the name has a fast slot.
KOS_OP_JUMP_OR_VAR
Style: EXTRA (VAR, LABEL, NOARG, NOARG). Row = name, target pc.
Stack:
[...] -> [..., x]on the jump,[...] -> [...]on the fall-through. Read the value the name resolves to in the current frame’s namespace; if true, push it and jump to the target; if false, advance with nothing pushed. RaisesNameErrorwhen the name is unbound.Invariants: Jump locality for target.
Compiler form: Produced by
ByteCodeProcessor.fuse_feedersabsorbing a bareVARload into theJUMP_ORit feeds. Lowers to JUMP_OR_FAST when the name has a fast slot.
KOS_OP_JUMP_AND_FAST
Style: EXTRA (FASTVAR, LABEL, NOARG, NOARG). Row = fast slot, target pc.
Stack:
[...] -> [..., x]on the jump,[...] -> [...]on the fall-through. Read the fast slot; if false, push the value and jump to the target; if true, advance with nothing pushed and no reference taken. RaisesNameErrorwhen the slot is empty.Invariants: Jump locality for target.
Compiler form: Post-compile only: the
convert_fastlowering of JUMP_AND_VAR when the name has a fast slot.
KOS_OP_JUMP_OR_FAST
Style: EXTRA (FASTVAR, LABEL, NOARG, NOARG). Row = fast slot, target pc.
Stack:
[...] -> [..., x]on the jump,[...] -> [...]on the fall-through. Read the fast slot; if true, push the value and jump to the target; if false, advance with nothing pushed and no reference taken. RaisesNameErrorwhen the slot is empty.Invariants: Jump locality for target.
Compiler form: Post-compile only: the
convert_fastlowering of JUMP_OR_VAR when the name has a fast slot.
Example: (or x default) in value position, both in fast slots.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
JUMP_OR_FAST |
0 |
(fast 0 (“x”), -> 2, 0, 0) |
x true: push x, pc=2 |
1 |
FAST |
1 |
1 (local “default”) |
stack: […, default] |
2 |
RETURN |
1 |
1 |
9. Check jumps
Check jumps: jump to the target label when the predicate does not hold. Jump locality applies to every target. The comparison check is the selector-keyed CHECK_COMPARE, EXTRA with a (CMP, COUNT, LABEL, RAW) row: a0 is a KosCompare selector, a1 the operand count (>= 2), a2 the target pc, a3 the negate flag. It is variadic – the top COUNT operands are chain-compared left-to-right under the selector (e.g. a < b < c), negated when a3 is set, and the jump is taken when the chain fails. IS, IS_NOT, IN and NOT_IN are strictly binary at this opcode; IS_INSTANCE and IS_SUBCLASS test the first operand against every operand after it. The remaining checks (exception, nil) take a single LABEL arg.
KOS_OP_CHECK_COMPARE
Style: EXTRA (CMP, COUNT, LABEL, RAW). Row = KosCompare selector, operand count, target pc, negate flag.
Stack:
[..., a1, ..., aN] -> [...]. Chain-compare the top COUNT operands under the selector, negated when the negate flag is set; jump to LABEL when the chain fails. The operands are dropped either way. RaisesTypeErrorwhenCOUNT < 2.Invariants: Selector is a valid KosCompare ordinal. The richcompare six (LT/LE/EQ/NE/GT/GE, ordinals 0-5 == CPython’s Py_LT..Py_GE) chain over any COUNT; IS, IS_NOT, IN and NOT_IN require COUNT == 2; IS_INSTANCE and IS_SUBCLASS take any COUNT >= 2.
Compiler form: Produced by
Compiler.compressfusingOBJECT_COMPARE+JUMP_FALSEinto one instruction, andOBJECT_COMPARE+JUMP_TRUEinto the same with the flag set. Never emitted directly by specials.
Example: Branch unless 1 < x < 100. Selector LT = 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (1) |
stack: […, 1] |
1 |
FAST |
0 |
0 (x) |
stack: […, 1, x] |
2 |
CONST |
1 |
1 (100) |
stack: […, 1, x, 100] |
3 |
CHECK_COMPARE |
0 |
(LT, 3, -> 6, 0) |
jump to 6 unless 1 < x < 100 |
KOS_OP_CHECK_COMPARE_VAR
Style: EXTRA (CMPSRC, VAR, VAR, LABEL). Row = packed selector + source bits, two operand slots, target pc; the negate bit makes the check test the negated comparison. A set source bit overrides that operand slot from its declared VAR kind to CONST (pool index).
Stack: No stack effect. Arity-2 fused comparison branch: load both operands per the source bits (frame namespace name lookup, or constant pool), compare under the selector, jump to LABEL when the comparison, negated under a set negate bit, fails.
Invariants: Selector is a valid KosCompare ordinal; both-CONST rows are never emitted (that is a folding case).
Compiler form: Produced by
ByteCodeProcessor.fuse_feeders(latecompresssweep) absorbing two bare VAR/CONST feeder rows into an arity-2 CHECK_COMPARE. Runs beforepack_var_runsso this fusion gets first claim on the feeders. Lowers to CHECK_COMPARE_FAST via the CMPSRC-awareconvert_fastcase (all-or-nothing on the name slots).Implementation:
koskari/lib/opcode/CHECK_COMPARE_VAR.c(cold handler)Covered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_compare.py
Example: Loop condition i < n on fast slots 1 and 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
3 |
CHECK_COMPARE_VAR |
2 |
(LT, v#1 (‘i’), v#0 (‘n’), -> 9) |
jump to 9 unless i < n |
KOS_OP_CHECK_COMPARE_FAST
Style: EXTRA (CMPSRC, FASTVAR, FASTVAR, LABEL). Row = packed selector + source bits, two operand slots, target pc; the negate bit makes the check test the negated comparison. A set source bit overrides that operand slot from its declared FASTVAR kind to CONST (pool index).
Stack: No stack effect. Arity-2 fused comparison branch: load both operands per the source bits (fast local slot, or constant pool), compare under the selector, jump to LABEL when the comparison, negated under a set negate bit, fails.
Invariants: Selector is a valid KosCompare ordinal; both-CONST rows are never emitted (that is a folding case).
Compiler form: Post-compile only: the CMPSRC-aware
convert_fastlowering of CHECK_COMPARE_VAR when every name-sourced slot has a fast slot. Constant-bit slots pass through untouched.Implementation:
koskari/lib/opcode/CHECK_COMPARE_FAST.cCovered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_compare.py
Example: Loop condition i < n on fast slots 1 and 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
3 |
CHECK_COMPARE_FAST |
2 |
(LT, fast 1 (“i”), fast 0 (“n”), -> 9) |
jump to 9 unless i < n |
KOS_OP_CHECK_EXCEPTION
Style: LABEL. Arg = target pc (post-compile).
Stack: Pop TOS (exception type or tuple of types). If current exception matches that value, leave PC unchanged; else set PC to arg (branch to next handler).
Invariants: Jump locality for target. Used inside exception handling path.
Compiler form: Pre-compile arg = string label (next handler or re-raise); post-compile arg = pc.
Example: In except block: type(s) on stack; pop and match; jump if no match.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
3 |
CONST |
0 |
0 (typ) |
stack: […, typ] |
4 |
CHECK_EXCEPTION |
7 |
7 (-> 7) |
pop typ; if exc not match -> pc=7 |
5 |
POP |
1 |
1 |
consume exc |
6 |
RETURN |
1 |
1 |
handle |
7 |
LABEL |
– |
– |
re-raise or next handler |
9.1 Switch dispatch
Switch dispatch opcodes implement multi-way equality branching. A typical checks region runs comparisons in order: each comparison falls through when it does not match so the next check can run without re-pushing the scrutinee. A match jumps into a shared body (or the same body for several keys).
KOS_OP_SWITCH_EQ compares two stack operands, discriminant left
below key right (TOS). On match, both are popped and the PC is set
to arg (the body). On mismatch, only right is popped; left
remains so the following code can push another key and use another
SWITCH_EQ.
The single-slot variants (SWITCH_EQ_CONST, SWITCH_EQ_VAR, …)
compare the scrutinee s at TOS to an RHS from the extra row. On
match, s is popped and the PC jumps to a0. On mismatch,
the stack is unchanged and execution falls through.
See compile/switch for the surface form and Switch dispatch (section 9.1) for the opcode family.
KOS_OP_SWITCH_EQ
Style: LABEL. Arg = target pc (post-compile).
Stack:
[..., left, right](right = TOS). Comparesleft == rightwith the same equality semantics as CHECK_COMPARE EQ (PyObject_RichCompareBoolwithPy_EQ).Match: pop both operands;
pc = arg. Stack after:[...].Mismatch: pop
rightonly; fall through. Stack after:[..., left].
Invariants: Jump target is the matching body. After a mismatch, bytecode must leave
leftcorrect for the next comparison (push a newright) or reach cleanup that dropsleft.Compiler form: Pre-compile arg = string label (body); post-compile arg = pc.
Example: Two-arm chain then else. Pool: 0 = 10, 1 = 1, 2 = 20, 3 = 2, 4 =
0. Discriminant 10: first key 1 (mismatch – pop key, fall through with [10]);
second key 20 (match – pop both, jump to body); body returns 2. Else drops
disc and returns 0. Covered by tests/lib/opcode/test_switch.py.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (10) |
stack: […, 10] |
1 |
CONST |
1 |
1 (1) |
stack: […, 10, 1] |
2 |
SWITCH_EQ |
8 |
8 (-> 8) |
match -> pop2, pc=8 (body); mismatch -> […, 10], next insn |
3 |
CONST |
2 |
2 (20) |
stack: […, 10, 20] |
4 |
SWITCH_EQ |
8 |
8 (-> 8) |
match -> body; mismatch -> […, 10], next insn |
5 |
POP |
1 |
1 |
else: drop discriminant |
6 |
CONST |
4 |
4 (0) |
else result |
7 |
RETURN |
1 |
1 |
|
8 |
LABEL |
– |
– |
body |
9 |
CONST |
3 |
3 (2) |
stack: […, 2] |
10 |
RETURN |
1 |
1 |
KOS_OP_SWITCH_EQ_CONST
Style: EXTRA. Schema
(LABEL, CONST, NOARG, NOARG).Stack:
[..., s]. Compares == cpool[a1]withPy_EQ.Match: pop
s;pc = a0.Mismatch: fall through; stack unchanged (
sstill TOS).
Compiler form: tuple arg
("label", const_value, 0, 0)pre-compile; post-compile row stores pc ina0and constant index ina1.Implementation:
koskari/lib/opcode/SWITCH_EQ_CONST.c
KOS_OP_SWITCH_EQ_VAR
Style: EXTRA. Schema
(LABEL, VAR, NOARG, NOARG).Stack:
[..., s]. Readrhsfrom the frame namespace by the name ina1, then compares == rhs.Match: pop
s;pc = a0.Mismatch: fall through; stack unchanged.
Compiler form: tuple arg
("label", "name", 0, 0)pre-compile.
KOS_OP_SWITCH_EQ_FAST
Style: EXTRA. Schema
(LABEL, FASTVAR, NOARG, NOARG).Stack:
[..., s]. Resolverhs = KosNamespace_FastDeref(ns, a1), then compares == rhswithPy_EQ.Match: pop
s;pc = a0.Mismatch: fall through; stack unchanged.
Compiler form: tuple arg
("label", slot_index, 0, 0)pre-compile.Implementation:
koskari/lib/opcode/SWITCH_EQ_FAST.c
KOS_OP_SWITCH_EQ_VAR_ATTR
Style: EXTRA. Schema
(LABEL, VAR, CONST, NOARG).Stack:
[..., s]. Readobjfrom the frame namespace by the name ina1, thenrhs = getattr(obj, attr_name)with the name ina2, then compares == rhs.Match: pop
s;pc = a0.Mismatch: fall through; stack unchanged.
Compiler form: tuple arg
("label", "obj_name", "attr_name", 0)pre-compile.
KOS_OP_SWITCH_EQ_FAST_ATTR
Style: EXTRA. Schema
(LABEL, FASTVAR, CONST, NOARG).Stack:
[..., s]. Resolveobj = KosNamespace_FastDeref(ns, a1),rhs = getattr(obj, attr_name)froma2, then compares == rhs.Match: pop
s;pc = a0.Mismatch: fall through; stack unchanged.
Compiler form: tuple arg
("label", slot_index, "attr_name", 0)pre-compile.Implementation:
koskari/lib/opcode/SWITCH_EQ_FAST_ATTR.c
9.2 Pattern matching
The MATCH_* instructions carry a compiled pattern. A match arm, a
special form’s pattern and a syntax-rules rule compile to a run of
these instructions in the code that uses them; no pattern object is
interpreted at run time.
Walk entries. A walk keeps its state on the operand stack as entries of three kinds. A cursor walks one subject – a pair spine, a tuple, list or other sequence, or a single value as a one-element subject – and has a position and an end. A mark has the position of the cursor it was made at, which never moves, and a fixed count of slots, each empty or holding one capture; it is the record of one capture scope. An items list collects a repeat’s passes; the repeat pushes it empty with
BUILD_LIST 0.Depths. A RAW field names a walk entry by its depth: the count of entries above it as the instruction finds the stack, 0 the top before the instruction pops or pushes. A depth that names a cursor or mark where the entry is of another kind raises
SystemError.Copy on write. An instruction that moves a cursor, writes a mark’s slots or appends to an items list writes the entry it names. When another stack entry holds the same object – after a
DUP, or in a continuation captured during the walk – the instruction stores a copy at its entry and writes the copy, so a resumed continuation sees the cursors, marks and items it captured.Misses. An instruction with a LABEL field jumps there on a miss.
Tests.
MATCH_LITERAL,MATCH_CORE,MATCH_TYPE_*,MATCH_CLASS_*,MATCH_SAMEandMATCH_MAPPINGread TOS and leave it on a hit and on a miss; the code after the test removes the value.Boxing. An element pulled from a pair spine is a
Datumcarrying its cell’s position; an element of a tuple, list or single value is the item itself. Every test reads throughDatum.Twins. A type, class or mapping key the pattern names is a variable of the enclosing code. An instruction that reads one has a
_VARform, with a VAR field read by name, and a_FASTform, with a FASTVAR field read by fast index;convert_fastlowers the one to the other as for everyVARinstruction. An instruction with no such field has one form under its bare name.Calls. A predicate or extractor is a variable called with
CALL_VARfrom the same frame, and flattens as any Koskari call does; a predicate’s result is tested withJUMP_FALSE.Core types. Seven type names are not variables:
pair,symbol,keyword,int,str,tupleandlistin a pattern lower toMATCH_CORE, which carries the type as an ordinal in a RAW field. A binding of one of those names in scope is never read by a pattern.Widths. Width and count fields are 16 bits; in
MATCH_FITSa maximum of0xFFFFis unbounded.
Instruction |
Reference |
|---|---|
MATCH_DESCEND |
|
MATCH_SINGLE |
|
MATCH_FITS |
|
MATCH_NEXT |
|
MATCH_BOUND |
|
MATCH_UNBOUND |
|
MATCH_SYNC |
|
MATCH_TAIL |
|
MATCH_SCOPE |
|
MATCH_SCOPE_NEXT |
|
MATCH_RESET |
|
MATCH_AT |
|
MATCH_SPAN |
|
MATCH_STORE |
|
MATCH_CLEAR |
|
MATCH_CAPTURES |
|
MATCH_PASS |
|
MATCH_LOAD |
|
MATCH_APPEND |
|
MATCH_MIN |
|
MATCH_COLUMNS |
|
MATCH_LITERAL |
|
MATCH_CORE |
|
MATCH_TYPE_VAR / MATCH_TYPE_FAST |
|
MATCH_CLASS_VAR / MATCH_CLASS_FAST |
|
MATCH_SAME |
|
MATCH_FIELD_POS_VAR / MATCH_FIELD_POS_FAST |
|
MATCH_FIELD_KW |
|
MATCH_MAPPING |
|
MATCH_KEY |
|
MATCH_KEY_VAR / MATCH_KEY_FAST |
10. Introspection
KOS_OP_GLOBALS
Style: NOARG.
Stack:
[...] -> [..., globals_dict].Invariants: Frame has globals namespace.
Example: Push frame’s globals dict.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
GLOBALS |
0 |
0 |
stack: […, globals_dict] |
1 |
RETURN |
1 |
1 |
KOS_OP_LOCALS
Style: NOARG.
Stack:
[...] -> [..., locals_dict].Invariants: Frame has locals namespace.
Example: Push frame’s locals dict.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
LOCALS |
0 |
0 |
stack: […, locals_dict] |
1 |
RETURN |
1 |
1 |
10.1 Module import
The three import opcodes each implement one Koskari import surface form. They
are self-contained and stack-neutral: each carries the module name and
relative-import level in its EXTRA row, imports its own module, and stores its
own bindings into the current frame namespace. None of them touch the operand
stack, chain a module between instructions, or need a compensating POP. See
koskari/compile/specials/imports.py (special_import, special_import_from,
special_import_all_from) for the compiler forms.
For a relative import (level > 0), the resolver builds a temporary globals
dict holding __name__ / __package__ from the frame’s globals namespace so
PyImport_ImportModuleLevelObject can resolve the anchor package. A leaf
import passes the sentinel _import_fromlist = ("*",) to return the deepest
submodule; a root import passes a NULL fromlist to return the root package
while still importing the full dotted chain (matching a plain Python
import foo.bar).
KOS_OP_IMPORT
Style: EXTRA (
CONST,COUNT,COUNT,CONST). Row:a0= cpool module name str (or None for a bare relative import),a1= level (leading dots; 0 = absolute),a2= leaf flag (0 = bind root, 1 = bind leaf),a3= cpool binding name str.Stack: no effect.
Semantics: Import the module (root or leaf per the flag) and store it into the current frame namespace under the binding name. With the leaf flag clear the root package is bound while the full dotted chain is still imported – plain
(import foo.bar)bindsfoo; with it set the deepest submodule is bound – the(import [foo.bar as: fbar])member form. Relative imports are always leaf-style. Self-contained: no stack effect, no separate VAR_BIND.Invariants:
a0is a str or None;a3is a str.Implementation:
koskari/lib/opcode/IMPORT.c
Example: (import os.path) – import the os.path chain, bind the root
os. Extra row: ("os.path", 0, 0, "os").
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
IMPORT |
0 |
0 (“os.path”, 0, 0, “os”) |
bind “os”; stack: […] |
1 |
CONST |
1 |
1 (None) |
statement value; stack: […, None] |
2 |
RETURN |
1 |
1 |
Member form (import [os.path as: p]) uses row ("os.path", 0, 1, "p") to
bind the leaf; relative (import .foo) uses ("foo", 1, 1, "foo").
KOS_OP_IMPORT_FROM
Style: EXTRA (
CONST,COUNT,CONST,CONST). Row:a0= cpool module name str (or None),a1= level,a2= cpool tuple of attribute names,a3= cpool tuple of binding names (parallel to the attribute names; the same tuple object when there are no renames).Stack: no effect.
Semantics: Import the leaf module, then for each attribute name
getattrit and store the value into the current frame namespace under the corresponding binding name. Self-contained: no module on the stack, no compensating POP.Submodule fallback: when the
getattrraisesAttributeError, import"{module.__name__}.{attr}"and retry – matching CPython’sfrom pkg import subbehavior for submodules the package__init__does not import. Other exceptions propagate.Invariants:
a2anda3are equal-length tuples of str.Implementation:
koskari/lib/opcode/IMPORT_FROM.c
Example: (import-from os path [sep as: s]) – import os, bind path and
bind sep as s. Extra row: ("os", 0, ("path", "sep"), ("path", "s")).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
IMPORT_FROM |
0 |
0 (“os”, 0, (“path”,”sep”), …) |
bind “path”, “s”; stack: […] |
1 |
CONST |
1 |
1 (None) |
statement value |
2 |
RETURN |
1 |
1 |
KOS_OP_IMPORT_STAR
Style: EXTRA (
CONST,COUNT,NOARG,NOARG). Row:a0= cpool module name str (or None),a1= level.Stack: no effect.
Semantics: Import the leaf module and bind its public names into the current frame namespace, matching Python’s
from MODULE import *. Name selection follows CPython’simport_all_from: when the module defines__all__(a sequence of str; a non-str entry is aTypeError) exactly those names are bound; otherwise everydir(module)name that does not start with an underscore. Existing bindings are overwritten.Compiler restriction: the
import-all-fromspecial emits this opcode only at module top level; it is a compile error inside a function, lambda,let, or class body.Invariants:
a0is a str or None.Implementation:
koskari/lib/opcode/IMPORT_STAR.c
Example: (import-all-from os.path) – bind os.path’s public names. Extra
row: ("os.path", 0, 0, 0).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
IMPORT_STAR |
0 |
0 (“os.path”, 0, …) |
bind public names; stack: […] |
1 |
CONST |
1 |
1 (None) |
statement value |
2 |
RETURN |
1 |
1 |
KOS_OP_IMPORT_USE
Style: EXTRA (
CONST,COUNT,CONST,CONST). Row:a0= cpool module name str (or None),a1= level,a2= cpool tuple of feature stems,a3= cpool tuple of bind stems (parallel to the feature stems; the same tuple object when there are no renames).Stack: no effect.
Semantics: Import the leaf module, then for each feature stem probe its candidate set – the stem itself,
compile/{stem}, andlayout/{stem}– and store each hit into the current frame namespace under the parallel bind stem with the same facet prefix applied, so a rename substitutes the whole family. A stem already carrying a facet prefix is literal: one candidate, bound as written. Self-contained: no module on the stack, no compensating POP.Miss handling: a per-facet miss is tolerated. The bare candidate uses the same member fetch as
IMPORT_FROM(submodule fallback included); its crafted missing-memberImportErrorcounts as a miss, while aModuleNotFoundErrorfrom inside a submodule’s own import propagates. A stem with zero hits raisesImportErrornaming the spellings tried.Compiler restriction: the
usespecial emits this opcode only at module top level.Invariants:
a2anda3are equal-length tuples of str.Implementation:
koskari/lib/opcode/IMPORT_USE.c
Example: (use tacotruck tacos) where the module defines tacos and
compile/tacos – bind both. Extra row: ("tacotruck", 0, ("tacos",), ("tacos",)).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
IMPORT_USE |
0 |
0 (“tacotruck”, 0, (“tacos”,), …) |
bind “tacos”, “compile/tacos”; stack: […] |
1 |
CONST |
1 |
1 (None) |
statement value |
2 |
RETURN |
1 |
1 |
Note: There is no KOS_OP_CAPTURE_FRAME (or similar) in koskari/lib/opcodes.incl; a future opcode would be added there first, then documented here.
11. Exception handling
KOS_OP_EXCEPTION
Style: NOARG.
Stack:
[...] -> [..., exception]. Push current exception (in handler).Invariants: Used when an exception is being handled.
Example: In except block: load current exception.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
EXCEPTION |
0 |
0 |
stack: […, exc] |
3 |
VAR_STORE |
0 |
0 (e) |
store exc in name “e” |
KOS_OP_EXCEPTION_CLEAR
Style: NOARG.
Stack: No change. Clear current exception state.
Invariants: – Example: After handling, clear exception before continuing.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
4 |
EXCEPTION_CLEAR |
0 |
0 |
clear exception state |
5 |
RETURN |
1 |
1 |
KOS_OP_EXCEPTION_MATCH
Style: NOARG.
Stack: Pop TOS (exception type or tuple of types). Push True if current exception matches that value, else False.
Invariants: Used in handler. Compiler typically emits BUILD_ARGS before this to pack multiple types into one tuple.
Example: Match current exception against one type; push True/False.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
CONST |
0 |
0 (ValueError) |
stack: […, typ] |
3 |
EXCEPTION_MATCH |
0 |
0 |
stack: […, result] |
4 |
JUMP_FALSE |
7 |
7 (-> 7) |
if no match, next handler |
12. Variables by name
KOS_OP_VAR
Style: VAR. Arg = constant pool index of variable name (post-compile).
Stack:
[...] -> [..., value]. Load value bound to name in frame namespace.Invariants: Name in constant pool.
Compiler form: Pre-compile arg = name (string/symbol); finalize stores name in pool and rewrites arg to pool index. May be lowered to FAST with slot index for locals.
Example: Load variable “x”. Pool: 0 = “x”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘x’) |
stack: […, value] |
1 |
RETURN |
1 |
1 |
KOS_OP_VAR2
Style: EXTRA (VAR, VAR, NOARG, NOARG). Row = two constant pool name indices (post-compile).
Stack:
[...] -> [..., a, b]. Load both names from the frame namespace and push in row order. Both names resolve before either push, so a missing name errors with nothing pushed.Invariants: Names in constant pool.
Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs(the trailing pack phase), which combines a run of two consecutive bare VAR loads (quads first, then one triple or one pair).convert_fastlowers to FAST2 when both names have fast slots (all-or-nothing; a mixed-eligibility row stays VAR2).Implementation:
koskari/lib/opcode/VAR2.c(cold handler)Covered by:
tests/compile/test_pack_var_runs.py,tests/reproducers/test_var_pack.py
Example: Load “x” then “y”. Pool: 0 = “x”, 1 = “y”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR2 |
0 |
(0 (‘x’), 1 (‘y’), 0, 0) |
stack: […, x, y] |
1 |
RETURN |
1 |
1 |
KOS_OP_VAR3
Style: EXTRA (VAR, VAR, VAR, NOARG). Row = three constant pool name indices (post-compile).
Stack:
[...] -> [..., a, b, c]. Load the three names from the frame namespace and push in row order. Every name resolves before any push, so a missing name errors with nothing pushed.Invariants: Names in constant pool.
Compiler form: As VAR2: produced only by
ByteCodeProcessor.pack_runsfrom a run of three consecutive bare VAR loads (quads first, then one triple or one pair).convert_fastlowers to FAST3 when all three names have fast slots (all-or-nothing; a mixed-eligibility row stays VAR3).Implementation:
koskari/lib/opcode/VAR3.c(cold handler)Covered by:
tests/compile/test_pack_var_runs.py,tests/reproducers/test_var_pack.py
Example: Load “a”, “b”, “c”. Pool: 0-2 = names.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR3 |
0 |
(0 (‘a’), 1 (‘b’), 2 (‘c’), 0) |
stack: […, a, b, c] |
1 |
RETURN |
1 |
1 |
KOS_OP_VAR4
Style: EXTRA (VAR, VAR, VAR, VAR). Row = four constant pool name indices (post-compile).
Stack:
[...] -> [..., a, b, c, d]. Load all four names from the frame namespace and push in row order. All names resolve before any push, so a missing name errors with nothing pushed.Invariants: Names in constant pool.
Compiler form: As VAR2: produced only by
pack_runsfrom a run of four (or more, greedily) consecutive bare VAR loads.convert_fastlowers to FAST4 when all four names have fast slots.Implementation:
koskari/lib/opcode/VAR4.c(cold handler)Covered by:
tests/compile/test_pack_var_runs.py,tests/reproducers/test_var_pack.py
Example: Load “a”, “b”, “c”, “d”. Pool: 0-3 = names.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR4 |
0 |
(0 (‘a’), 1 (‘b’), 2 (‘c’), 3 (‘d’)) |
stack: […, a, b, c, d] |
1 |
RETURN |
1 |
1 |
KOS_OP_VAR_BIND
Style: VAR. Arg = constant pool index of name (post-compile).
Stack:
[..., ref] -> [...]. BIND: use this reference to resolve the given name in the frame namespace. See section 1.9.Invariants: Name in constant pool.
Compiler form: Pre-compile arg = name (string/symbol); post-compile arg = pool index.
Example: Bind name “n” to the reference at TOS. Pool: 0 = “n”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (42) |
stack: […, ref] |
1 |
VAR_BIND |
1 |
1 (‘n’) |
BIND: name “n” resolves to this ref; stack: […] |
KOS_OP_VAR_CLEAR
Style: VAR. Arg = constant pool index of name (post-compile).
Stack: No stack effect. Delete name from namespace.
Invariants: Name in constant pool.
Compiler form: Pre-compile arg = name; post-compile arg = pool index.
Example: Delete name “tmp”. Pool: 0 = “tmp”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
VAR_CLEAR |
0 |
0 (‘tmp’) |
delete “tmp” from namespace |
KOS_OP_VAR_CLEAR2
Style: EXTRA (VAR, VAR, NOARG, NOARG). Row = 2 constant pool name indices (post-compile).
Stack: No stack effect. Clear the 2 names in row order, as 2
VAR_CLEARwould; an already empty one stays empty.Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs, which combines a run of consecutiveVAR_CLEARinstructions (quads first, then one triple or one pair).
KOS_OP_VAR_CLEAR3
Style: EXTRA (VAR, VAR, VAR, NOARG). Row = 3 constant pool name indices (post-compile).
Stack: No stack effect. Clear the 3 names in row order, as 3
VAR_CLEARwould; an already empty one stays empty.Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs, which combines a run of consecutiveVAR_CLEARinstructions (quads first, then one triple or one pair).
KOS_OP_VAR_CLEAR4
Style: EXTRA (VAR, VAR, VAR, VAR). Row = 4 constant pool name indices (post-compile).
Stack: No stack effect. Clear the 4 names in row order, as 4
VAR_CLEARwould; an already empty one stays empty.Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs, which combines a run of consecutiveVAR_CLEARinstructions (quads first, then one triple or one pair).
KOS_OP_VAR_TAKE
Style: VAR. Arg = constant pool index of name (post-compile).
Stack:
[...] -> [..., value]. Deref name viaframe_ns_take, clear the binding, push the value. Errors with NameError if the binding is empty (contrast VAR_CLEAR, which is idempotent on an already-empty declared slot).Invariants: Name in constant pool; binding must hold a value.
Compiler form: Pre-compile arg = name; post-compile arg = pool index. Emitted by compile/takeq. May lower to FAST_TAKE via fast-local lowering.
Example: Take and clear name “tmp”. Pool: 0 = “tmp”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
VAR_TAKE |
0 |
0 (‘tmp’) |
take “tmp”; stack: […, value] |
KOS_OP_VAR_REF
Style: VAR. Arg = constant pool index of name (post-compile).
Stack:
[...] -> [..., ref]. Push a reference to the named variable (e.g. for closure).Invariants: Name in constant pool.
Compiler form: Pre-compile arg = name; post-compile arg = pool index.
Example: Push reference for “cell”. Pool: 0 = “cell”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR_REF |
0 |
0 (‘cell’) |
stack: […, ref] |
KOS_OP_VAR_STORE
Style: VAR. Arg = constant pool index of name (post-compile).
Stack:
[..., value] -> [...]. STORE: store this value in the given name (through the reference that already resolves it). See section 1.9.Invariants: Name must already be bound.
Compiler form: Pre-compile arg = name; post-compile arg = pool index.
Example: Store value 10 into name “x”. Pool: 0 = “x”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (10) |
stack: […, 10] |
1 |
VAR_STORE |
1 |
1 (‘x’) |
STORE: write 10 into name “x”; stack: […] |
KOS_OP_VAR_STORE_CONST
Style: EXTRA (VAR, CONST, NOARG, NOARG). Arg = extra-table index (post-compile).
Stack:
[...] -> [...](no stack effect). STORE: store the constant value into the given name viaframe_ns_store. Same semantics as VAR_STORE, but the value is taken from the constant pool (extra row fielda1), not from TOS.Peephole:
Compiler.compressfusesKOS_OP_CONSTvalueimmediately followed byKOS_OP_VAR_STOREnameinto this opcode with pre-compile arg(name, value, None, None); theCONSTis removed from the stream. See section 1.8.Lowering:
Compiler.convert_fast(when the name has a fixed fast slot in FUNCTION mode) may replaceVAR_STORE_CONSTwithFAST_STORE_CONST, rewriting the VAR field to a slot index and preserving the constant operand.Invariants: Name must already be bound. Name and value are internalized into the extra row at finalize.
Compiler form: Pre-compile arg = 4-tuple
(name, value, None, None); post-compile arg = extra index.Implementation:
koskari/lib/opcode/VAR_STORE_CONST.cCovered by:
tests/compile/test_compress.py,tests/compile/test_convert_fast.py,tests/lib/opcode/test_store_const.py
Example: Store constant 42 into name "x" without pushing 42. Pre-compile stream after compress: one VAR_STORE_CONST; pool/extra filled at finalize. Post-compile arg view uses extra index 0 (illustrative).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR_STORE_CONST |
0 |
0 -> (‘x’, 42, …) |
STORE 42 into “x”; stack unchanged |
1 |
RETURN |
1 |
1 |
Example (fusion source): (setq x 42) emits value, VAR_STORE, CONST None; compress turns CONST 42 + VAR_STORE x into VAR_STORE_CONST.
KOS_OP_VAR_INPLACE
Style: EXTRA (OPERAND, VAR). Row a0 = the bare KosOperand selector; a1 = constant pool index of the variable name.
Stack:
[..., rhs] -> [...]. Augmented assignment through the frame namespace: obj = deref(name); obj OP= rhs; store back. No value pushed.Compiler form: Emitted by
compile/inplacewhen the target is a symbol. May lower to FAST_INPLACE; a single constant operand squashes into VAR_INPLACE_CONST.Implementation:
koskari/lib/opcode/VAR_INPLACE.c
KOS_OP_VAR_INPLACE_CONST
Style: EXTRA (OPERAND, VAR, CONST). Row a0 = bare KosOperand selector (the count is fixed at 1 by the shape), a1 = constant pool index of the name, a2 = constant pool index of the operand.
Stack: No stack effect. Augmented assignment with a constant rhs through the frame namespace, completely stack-free: obj = deref(name); obj OP= const; store back.
Peephole: the compressed form of CONST followed by VAR_INPLACE at a count of one, as VAR_STORE_CONST is of CONST and VAR_STORE. May lower to FAST_INPLACE_CONST.
Implementation:
koskari/lib/opcode/VAR_INPLACE_CONST.c
12.1 Attribute access on variables (VAR_ATTR_*)
These opcodes perform attribute get, set, clear, take, or reference on an object fetched from the frame namespace by name. The object is not on the stack; it is read from the frame namespace by name. Each uses EXTRA schema: VAR (obj name), CONST (attr name).
Compiler form: Emitted by attr/del-attr/take-attr/set-attr specials when the object expression is a symbol (variable reference). May be lowered to FAST_ATTR_* when the name has a fixed slot.
KOS_OP_VAR_ATTR
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get attribute on object held in namespace by name. Equivalent to ATTR but the object is loaded from the frame namespace, not from TOS.Implementation:
koskari/lib/opcode/VAR_ATTR.c
KOS_OP_VAR_ATTR_STORE
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[..., value] -> [...]. Set attribute. Equivalent to ATTR_STORE with object from namespace.Implementation:
koskari/lib/opcode/VAR_ATTR_STORE.c
KOS_OP_VAR_ATTR_CLEAR
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack: No stack effect. Delete attribute on object from namespace. Equivalent to ATTR_CLEAR with object from namespace.
Implementation:
koskari/lib/opcode/VAR_ATTR_CLEAR.c
KOS_OP_VAR_ATTR_TAKE
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get attribute on object from namespace, delete it, push value. Errors if attribute missing (same as VAR_ATTR + VAR_ATTR_CLEAR sequence).Compiler form: Emitted by compile/take-attr when OBJ is a symbol. May lower to FAST_ATTR_TAKE.
KOS_OP_VAR_ATTR_REF
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., attr_ref]. Push attribute reference. Equivalent to ATTR_REF with object from namespace.Implementation:
koskari/lib/opcode/VAR_ATTR_REF.c
KOS_OP_VAR_ATTR_INPLACE
Style: EXTRA (OPCOUNT, VAR, CONST, NOARG). Row a0 = operator selector and count, a1 = the object name, a2 = the attribute name.
Stack:
[..., v0 .. v_{n-1}] -> [...]. Resolve the object by name, reduce obj.attr in place with the count values left to right, store it back; pushes nothing (the special appends CONST None). Cold: the operator switch lives in the sharedkos_inplace_reduce.Compiler form: Emitted by
compile/inplace-attrwhen OBJ is a symbol. May lower to FAST_ATTR_INPLACE.Implementation:
koskari/lib/opcode/VAR_ATTR_INPLACE.c
KOS_OP_ITEM_STORE_VAR
Style: VAR (the value’s name).
Stack:
[..., obj, key] -> [...]. Set obj[key] = value with the object on the stack, the key on the stack and the value resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR value, ITEM_STORE. May lower to ITEM_STORE_FAST.Implementation:
koskari/lib/opcode/ITEM_STORE_VAR.c
KOS_OP_ITEM_CONST_STORE_VAR
Style: EXTRA (CONST, VAR, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key a pool constant and the value resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
CONST key, VAR value, ITEM_STORE, or fromVAR valueahead of the shaped ITEM_CONST_STORE. May lower to ITEM_CONST_STORE_FAST.Implementation:
koskari/lib/opcode/ITEM_CONST_STORE_VAR.c
KOS_OP_ITEM_VAR
Style: VAR (the key’s name).
Stack:
[..., obj] -> [..., value]. Get obj[key] with the object on the stack and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, ITEM. May lower to ITEM_FAST.Implementation:
koskari/lib/opcode/ITEM_VAR.c
KOS_OP_ITEM_VAR_CLEAR
Style: VAR (the key’s name).
Stack:
[..., obj] -> [...]. Delete obj[key] with the object on the stack and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, ITEM_CLEAR. May lower to ITEM_FAST_CLEAR.Implementation:
koskari/lib/opcode/ITEM_VAR_CLEAR.c
KOS_OP_ITEM_VAR_TAKE
Style: VAR (the key’s name).
Stack:
[..., obj] -> [..., value]. Get obj[key], delete it, and push the value with the object on the stack and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, ITEM_TAKE. May lower to ITEM_FAST_TAKE.Implementation:
koskari/lib/opcode/ITEM_VAR_TAKE.c
KOS_OP_ITEM_VAR_REF
Style: VAR (the key’s name).
Stack:
[..., obj] -> [..., value]. Push an ItemRef over obj[key] with the object on the stack and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, ITEM_REF. May lower to ITEM_FAST_REF.Implementation:
koskari/lib/opcode/ITEM_VAR_REF.c
KOS_OP_ITEM_VAR_STORE
Style: VAR (the key’s name).
Stack:
[..., obj, value] -> [...]. Set obj[key] = value with the object on the stack, the key resolved by name and the value on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/set-itemwhen OBJ is a symbol or KEY is a feeder and a value is not, so the fold could not reach the named operands. May lower to ITEM_FAST_STORE.Implementation:
koskari/lib/opcode/ITEM_VAR_STORE.c
KOS_OP_ITEM_VAR_STORE_CONST
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key resolved by name and the value a pool constant.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, CONST value, ITEM_STORE, or fromCONST valueahead of the shaped ITEM_VAR_STORE. May lower to ITEM_FAST_STORE_CONST.Implementation:
koskari/lib/opcode/ITEM_VAR_STORE_CONST.c
KOS_OP_ITEM_VAR_STORE_VAR
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key resolved by name and the value resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, VAR value, ITEM_STORE, or fromVAR valueahead of the shaped ITEM_VAR_STORE. May lower to ITEM_FAST_STORE_FAST.Implementation:
koskari/lib/opcode/ITEM_VAR_STORE_VAR.c
KOS_OP_ITEM_VAR_INPLACE
Style: EXTRA (OPCOUNT, VAR, NOARG, NOARG).
Stack:
[..., obj, v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object on the stack and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/inplace-itemwhen OBJ is a symbol or KEY is a feeder and a value is not, so the fold could not reach the named operands. May lower to ITEM_FAST_INPLACE.Implementation:
koskari/lib/opcode/ITEM_VAR_INPLACE.c
KOS_OP_ITEM_VAR_INPLACE_CONST
Style: EXTRA (OPERAND, VAR, CONST, NOARG).
Stack:
[..., obj] -> [...]. Reduce obj[key] in place with the pool constant and store it back with the object on the stack and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR key, CONST rhs, ITEM_INPLACEat a count of one, or fromCONST rhsahead of the shaped ITEM_VAR_INPLACE. May lower to ITEM_FAST_INPLACE_CONST.Implementation:
koskari/lib/opcode/ITEM_VAR_INPLACE_CONST.c
KOS_OP_VAR_ITEM
Style: VAR (the object’s name).
Stack:
[..., key] -> [..., value]. Get obj[key] with the object resolved by name and the key on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/itemwhen OBJ is a symbol and KEY is not a feeder, since no fold reaches an object load behind a computed key. May lower to FAST_ITEM.Implementation:
koskari/lib/opcode/VAR_ITEM.c
KOS_OP_VAR_ITEM_CLEAR
Style: VAR (the object’s name).
Stack:
[..., key] -> [...]. Delete obj[key] with the object resolved by name and the key on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/del-itemwhen OBJ is a symbol and KEY is not a feeder, since no fold reaches an object load behind a computed key. May lower to FAST_ITEM_CLEAR.Implementation:
koskari/lib/opcode/VAR_ITEM_CLEAR.c
KOS_OP_VAR_ITEM_TAKE
Style: VAR (the object’s name).
Stack:
[..., key] -> [..., value]. Get obj[key], delete it, and push the value with the object resolved by name and the key on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/take-itemwhen OBJ is a symbol and KEY is not a feeder, since no fold reaches an object load behind a computed key. May lower to FAST_ITEM_TAKE.Implementation:
koskari/lib/opcode/VAR_ITEM_TAKE.c
KOS_OP_VAR_ITEM_REF
Style: VAR (the object’s name).
Stack:
[..., key] -> [..., value]. Push an ItemRef over obj[key] with the object resolved by name and the key on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/ref-itemwhen OBJ is a symbol and KEY is not a feeder, since no fold reaches an object load behind a computed key. May lower to FAST_ITEM_REF.Implementation:
koskari/lib/opcode/VAR_ITEM_REF.c
KOS_OP_VAR_ITEM_STORE
Style: VAR (the object’s name).
Stack:
[..., key, value] -> [...]. Set obj[key] = value with the object resolved by name, the key on the stack and the value on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/set-itemwhen OBJ is a symbol and KEY is not a feeder, since no fold reaches an object load behind a computed key. May lower to FAST_ITEM_STORE.Implementation:
koskari/lib/opcode/VAR_ITEM_STORE.c
KOS_OP_VAR_ITEM_STORE_CONST
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[..., key] -> [...]. Set obj[key] = value with the object resolved by name, the key on the stack and the value a pool constant.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
CONST valueahead of VAR_ITEM_STORE, the rowcompile/set-itemshapes for a symbol object under a computed key. May lower to FAST_ITEM_STORE_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_STORE_CONST.c
KOS_OP_VAR_ITEM_STORE_VAR
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack:
[..., key] -> [...]. Set obj[key] = value with the object resolved by name, the key on the stack and the value resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR valueahead of VAR_ITEM_STORE, the rowcompile/set-itemshapes for a symbol object under a computed key. May lower to FAST_ITEM_STORE_FAST.Implementation:
koskari/lib/opcode/VAR_ITEM_STORE_VAR.c
KOS_OP_VAR_ITEM_INPLACE
Style: EXTRA (OPCOUNT, VAR, NOARG, NOARG).
Stack:
[..., key, v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object resolved by name and the key on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/inplace-itemwhen OBJ is a symbol and KEY is not a feeder, since no fold reaches an object load behind a computed key. May lower to FAST_ITEM_INPLACE.Implementation:
koskari/lib/opcode/VAR_ITEM_INPLACE.c
KOS_OP_VAR_ITEM_INPLACE_CONST
Style: EXTRA (OPERAND, VAR, CONST, NOARG).
Stack:
[..., key] -> [...]. Reduce obj[key] in place with the pool constant and store it back with the object resolved by name and the key on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
CONST operandahead of VAR_ITEM_INPLACE at a count of one, the rowcompile/inplace-itemshapes for a symbol object under a computed key. May lower to FAST_ITEM_INPLACE_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_INPLACE_CONST.c
KOS_OP_VAR_ITEM_CONST
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key] with the object resolved by name and the key a pool constant.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, ITEM. May lower to FAST_ITEM_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST.c
KOS_OP_VAR_ITEM_CONST_CLEAR
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack: No stack effect. Delete obj[key] with the object resolved by name and the key a pool constant.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, ITEM_CLEAR. May lower to FAST_ITEM_CONST_CLEAR.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_CLEAR.c
KOS_OP_VAR_ITEM_CONST_TAKE
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key], delete it, and push the value with the object resolved by name and the key a pool constant.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, ITEM_TAKE. May lower to FAST_ITEM_CONST_TAKE.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_TAKE.c
KOS_OP_VAR_ITEM_CONST_REF
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Push an ItemRef over obj[key] with the object resolved by name and the key a pool constant.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, ITEM_REF. May lower to FAST_ITEM_CONST_REF.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_REF.c
KOS_OP_VAR_ITEM_CONST_STORE
Style: EXTRA (VAR, CONST, NOARG, NOARG).
Stack:
[..., value] -> [...]. Set obj[key] = value with the object resolved by name, the key a pool constant and the value on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/set-itemwhen OBJ is a symbol, KEY is a feeder and a value is not, so the fold could not reach the named operands. May lower to FAST_ITEM_CONST_STORE.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_STORE.c
KOS_OP_VAR_ITEM_CONST_STORE_CONST
Style: EXTRA (VAR, CONST, CONST, NOARG).
Stack: No stack effect. Set obj[key] = value with the object resolved by name, the key a pool constant and the value a pool constant.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, CONST value, ITEM_STORE, or fromCONST valueahead of the shaped VAR_ITEM_CONST_STORE. May lower to FAST_ITEM_CONST_STORE_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_STORE_CONST.c
KOS_OP_VAR_ITEM_CONST_STORE_VAR
Style: EXTRA (VAR, CONST, VAR, NOARG).
Stack: No stack effect. Set obj[key] = value with the object resolved by name, the key a pool constant and the value resolved by name.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, VAR value, ITEM_STORE, or fromVAR valueahead of the shaped VAR_ITEM_CONST_STORE. May lower to FAST_ITEM_CONST_STORE_FAST.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_STORE_VAR.c
KOS_OP_VAR_ITEM_CONST_INPLACE
Style: EXTRA (OPCOUNT, VAR, CONST, NOARG).
Stack:
[..., v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object resolved by name and the key a pool constant.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/inplace-itemwhen OBJ is a symbol, KEY is a feeder and a value is not, so the fold could not reach the named operands. May lower to FAST_ITEM_CONST_INPLACE.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_INPLACE.c
KOS_OP_VAR_ITEM_CONST_INPLACE_CONST
Style: EXTRA (OPERAND, VAR, CONST, CONST).
Stack: No stack effect. Reduce obj[key] in place with the pool constant and store it back with the object resolved by name and the key a pool constant.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, CONST key, CONST rhs, ITEM_INPLACEat a count of one, or fromCONST rhsahead of the shaped VAR_ITEM_CONST_INPLACE. May lower to FAST_ITEM_CONST_INPLACE_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_CONST_INPLACE_CONST.c
KOS_OP_VAR_ITEM_VAR
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key] with the object resolved by name and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, ITEM. May lower to FAST_ITEM_FAST.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR.c
KOS_OP_VAR_ITEM_VAR_CLEAR
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack: No stack effect. Delete obj[key] with the object resolved by name and the key resolved by name.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, ITEM_CLEAR. May lower to FAST_ITEM_FAST_CLEAR.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_CLEAR.c
KOS_OP_VAR_ITEM_VAR_TAKE
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key], delete it, and push the value with the object resolved by name and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, ITEM_TAKE. May lower to FAST_ITEM_FAST_TAKE.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_TAKE.c
KOS_OP_VAR_ITEM_VAR_REF
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack:
[...] -> [..., value]. Push an ItemRef over obj[key] with the object resolved by name and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, ITEM_REF. May lower to FAST_ITEM_FAST_REF.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_REF.c
KOS_OP_VAR_ITEM_VAR_STORE
Style: EXTRA (VAR, VAR, NOARG, NOARG).
Stack:
[..., value] -> [...]. Set obj[key] = value with the object resolved by name, the key resolved by name and the value on the stack.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/set-itemwhen OBJ is a symbol, KEY is a feeder and a value is not, so the fold could not reach the named operands. May lower to FAST_ITEM_FAST_STORE.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_STORE.c
KOS_OP_VAR_ITEM_VAR_STORE_CONST
Style: EXTRA (VAR, VAR, CONST, NOARG).
Stack: No stack effect. Set obj[key] = value with the object resolved by name, the key resolved by name and the value a pool constant.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, CONST value, ITEM_STORE, or fromCONST valueahead of the shaped VAR_ITEM_VAR_STORE. May lower to FAST_ITEM_FAST_STORE_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_STORE_CONST.c
KOS_OP_VAR_ITEM_VAR_STORE_VAR
Style: EXTRA (VAR, VAR, VAR, NOARG).
Stack: No stack effect. Set obj[key] = value with the object resolved by name, the key resolved by name and the value resolved by name.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, VAR value, ITEM_STORE, or fromVAR valueahead of the shaped VAR_ITEM_VAR_STORE. May lower to FAST_ITEM_FAST_STORE_FAST.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_STORE_VAR.c
KOS_OP_VAR_ITEM_VAR_INPLACE
Style: EXTRA (OPCOUNT, VAR, VAR, NOARG).
Stack:
[..., v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object resolved by name and the key resolved by name.Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Shaped by
compile/inplace-itemwhen OBJ is a symbol, KEY is a feeder and a value is not, so the fold could not reach the named operands. May lower to FAST_ITEM_FAST_INPLACE.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_INPLACE.c
KOS_OP_VAR_ITEM_VAR_INPLACE_CONST
Style: EXTRA (OPERAND, VAR, VAR, CONST).
Stack: No stack effect. Reduce obj[key] in place with the pool constant and store it back with the object resolved by name and the key resolved by name.
Cache: none; a VAR row survives lowering only for a name with no fast slot.
Compiler form: Folded by the compress pipeline from
VAR obj, VAR key, CONST rhs, ITEM_INPLACEat a count of one, or fromCONST rhsahead of the shaped VAR_ITEM_VAR_INPLACE. May lower to FAST_ITEM_FAST_INPLACE_CONST.Implementation:
koskari/lib/opcode/VAR_ITEM_VAR_INPLACE_CONST.c
13. Fast variables
KOS_OP_FAST
Style: FASTVAR. Arg = fast local slot index.
Stack:
[...] -> [..., value]. Load from slot.Invariants: Slot index in range for frame.
Compiler form: Usually post-compile only: emitted when VAR is lowered to a fast local (arg = slot index). Compiler may emit FAST directly with slot index in both forms.
Example: Load fast local 0. Arg view: 0 (local name if known).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST |
0 |
0 (a) |
stack: […, value] |
1 |
RETURN |
1 |
1 |
KOS_OP_FAST2
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG). Row = two fast local slot indices.
Stack:
[...] -> [..., a, b]. Load both slots and push in row order. Both slots resolve before either push, so an unbound slot errors with nothing pushed.Invariants: Slot indices in range for frame.
Compiler form: Post-compile only:
convert_fastlowering of VAR2 when both names have fast slots. See section 13 FAST for the slot model.Implementation:
koskari/lib/opcode/FAST2.cCovered by:
tests/compile/test_pack_var_runs.py,tests/reproducers/test_var_pack.py
Example: Load fast locals 0 and 1.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST2 |
0 |
(fast 0 (a), fast 1 (b), 0, 0) |
stack: […, a, b] |
1 |
RETURN |
1 |
1 |
KOS_OP_FAST3
Style: EXTRA (FASTVAR, FASTVAR, FASTVAR, NOARG). Row = three fast local slot indices.
Stack:
[...] -> [..., a, b, c]. Load the three slots and push in row order. Every slot resolves before any push, so an unbound slot errors with nothing pushed.Invariants: Slot indices in range for frame.
Compiler form: Post-compile only:
convert_fastlowering of VAR3 when all three names have fast slots, orByteCodeProcessor.pack_runson a run of three bare FAST loads.Implementation:
koskari/lib/opcode/FAST3.cCovered by:
tests/compile/test_pack_var_runs.py,tests/reproducers/test_var_pack.py
Example: Load fast locals 0-2.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST3 |
0 |
(fast 0 (a), fast 1 (b), fast 2 (c), 0) |
stack: […, a, b, c] |
1 |
RETURN |
1 |
1 |
KOS_OP_FAST4
Style: EXTRA (FASTVAR, FASTVAR, FASTVAR, FASTVAR). Row = four fast local slot indices.
Stack:
[...] -> [..., a, b, c, d]. Load all four slots and push in row order. All slots resolve before any push, so an unbound slot errors with nothing pushed.Invariants: Slot indices in range for frame.
Compiler form: Post-compile only:
convert_fastlowering of VAR4 when all four names have fast slots.Implementation:
koskari/lib/opcode/FAST4.cCovered by:
tests/compile/test_pack_var_runs.py,tests/reproducers/test_var_pack.py
Example: Load fast locals 0-3.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST4 |
0 |
(fast 0 (a), fast 1 (b), fast 2 (c), fast 3 (d)) |
stack: […, a, b, c, d] |
1 |
RETURN |
1 |
1 |
KOS_OP_FAST_BIND
Style: FASTVAR. Arg = fast local slot index.
Stack:
[..., ref] -> [...]. BIND: use this reference to resolve the given slot (name). See section 1.9. Not interchangeable with FAST_STORE.Invariants: Slot index in range.
Compiler form: Typically post-compile (from VAR_BIND lowering) or compiler emits with slot index.
Example: Bind slot 0 to the reference at TOS.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (1) |
stack: […, ref] |
1 |
FAST_BIND |
0 |
0 (a) |
BIND: slot 0 resolves to this ref; stack: […] |
KOS_OP_FAST_CLEAR
Style: FASTVAR. Arg = fast local slot index.
Stack: No stack effect. Clear slot.
Invariants: Slot index in range.
Example: Clear slot 1.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
FAST_CLEAR |
1 |
1 |
clear slot 1 |
KOS_OP_FAST_CLEAR2
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG). Row = 2 fast slot indices (post-compile).
Stack: No stack effect. Clear the 2 fast slots in row order, as 2
FAST_CLEARwould; an already empty one stays empty.Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs, which combines a run of consecutiveFAST_CLEARrows (quads first, then one triple or one pair).
KOS_OP_FAST_CLEAR3
Style: EXTRA (FASTVAR, FASTVAR, FASTVAR, NOARG). Row = 3 fast slot indices (post-compile).
Stack: No stack effect. Clear the 3 fast slots in row order, as 3
FAST_CLEARwould; an already empty one stays empty.Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs, which combines a run of consecutiveFAST_CLEARrows (quads first, then one triple or one pair).
KOS_OP_FAST_CLEAR4
Style: EXTRA (FASTVAR, FASTVAR, FASTVAR, FASTVAR). Row = 4 fast slot indices (post-compile).
Stack: No stack effect. Clear the 4 fast slots in row order, as 4
FAST_CLEARwould; an already empty one stays empty.Compiler form: Never emitted by specials. Produced only by
ByteCodeProcessor.pack_runs, which combines a run of consecutiveFAST_CLEARrows (quads first, then one triple or one pair).
KOS_OP_FAST_TAKE
Style: FASTVAR. Arg = fast local slot index.
Stack:
[...] -> [..., value]. Take value from slot viaKosNamespace_FastTake(steal pointer on raw slots without extra INCREF), clear slot. Errors with NameError if slot is empty (contrast FAST_CLEAR, idempotent on empty declared slots).Invariants: Slot index in range; slot must hold a value.
Compiler form: Lowered from VAR_TAKE when name has a fixed slot.
Example: Take slot 1.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
FAST_TAKE |
1 |
1 |
take slot 1; stack: […, value] |
KOS_OP_FAST_REF
Style: FASTVAR. Arg = fast local slot index.
Stack:
[...] -> [..., ref]. Push reference to slot.Invariants: Slot index in range.
Example: Push reference to slot 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST_REF |
0 |
0 (a) |
stack: […, ref] |
KOS_OP_FAST_STORE
Style: FASTVAR. Arg = fast local slot index.
Stack:
[..., value] -> [...]. STORE: store this value in the given slot (through the reference that already resolves it). See section 1.9. Not interchangeable with FAST_BIND.Invariants: Slot must already be bound. Slot index in range.
Example: Store value 99 in slot 0.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (99) |
stack: […, 99] |
1 |
FAST_STORE |
0 |
0 (a) |
STORE: write 99 into slot 0; stack: […] |
KOS_OP_FAST_STORE_CONST
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG). Arg = extra-table index (post-compile).
Stack:
[...] -> [...](no stack effect). STORE: store the constant value into the given fast slot viaKosNamespace_FastStore. Same semantics as FAST_STORE, but the value is from the constant pool (extra rowa1), not TOS.Peephole: Not fused directly from
CONST+FAST_STOREincompresstoday; typically appears whenVAR_STORE_CONSTis lowered byconvert_fastfor a local or closure name.Invariants: Slot must already be bound; slot index in range; frame namespace must support fast locals (
KosNamespace_SupportsFast).Compiler form: Pre-compile arg = 4-tuple
(slot, value, None, None)(slot may be integer afterconvert_fast); post-compile arg = extra index.Implementation:
koskari/lib/opcode/FAST_STORE_CONST.cCovered by:
tests/compile/test_convert_fast.py,tests/lib/opcode/test_store_const.py
Example: Store constant 100 in slot 0 without pushing 100.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST_STORE_CONST |
0 |
0 -> (0, 100, …) |
STORE 100 in slot 0; stack unchanged |
1 |
FAST |
0 |
0 (a) |
stack: […, 100] |
2 |
RETURN |
1 |
1 |
KOS_OP_FAST_INPLACE
Style: EXTRA (OPERAND, FASTVAR). Row a0 = the bare KosOperand selector; a1 = fast slot index.
Stack:
[..., rhs] -> [...]. Augmented assignment on a fast slot: obj = deref(slot); obj OP= rhs; store back. No value pushed.Compiler form: The lowered form of VAR_INPLACE.
Implementation:
koskari/lib/opcode/FAST_INPLACE.c
KOS_OP_FAST_INPLACE_CONST
Style: EXTRA (OPERAND, FASTVAR, CONST). Row a0 = bare KosOperand selector (the count is fixed at 1 by the shape), a1 = fast slot index, a2 = constant pool index of the operand.
Stack: No stack effect. Augmented assignment with a constant rhs on a fast slot, completely stack-free: obj = deref(slot); obj OP= const; store back. A counted loop’s back-edge increment is this single dispatch.
Compiler form: The lowered form of VAR_INPLACE_CONST.
Implementation:
koskari/lib/opcode/FAST_INPLACE_CONST.c
13.1 Attribute access on fast locals (FAST_ATTR_*)
These opcodes perform attribute get, set, clear, take, or reference on an object fetched from the fast local slot. The object is not on the stack; it is resolved via the fast slot. Each uses EXTRA schema: FASTVAR (slot), CONST (attr name).
Compiler form: Emitted when VAR_ATTR_* is lowered (name has fixed slot).
KOS_OP_FAST_ATTR
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get attribute on object in fast slot. Equivalent to ATTR but object from slot.Implementation:
koskari/lib/opcode/FAST_ATTR.c
KOS_OP_FAST_ATTR_STORE
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[..., value] -> [...]. Set attribute on object in fast slot.Implementation:
koskari/lib/opcode/FAST_ATTR_STORE.c
KOS_OP_FAST_ATTR_CLEAR
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack: No stack effect. Delete attribute on object in fast slot.
Implementation:
koskari/lib/opcode/FAST_ATTR_CLEAR.c
KOS_OP_FAST_ATTR_TAKE
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get attribute on object in fast slot, delete it, push value.
KOS_OP_FAST_ATTR_REF
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., attr_ref]. Push attribute reference for object in fast slot.Implementation:
koskari/lib/opcode/FAST_ATTR_REF.c
KOS_OP_FAST_ATTR_INPLACE
Style: EXTRA (OPCOUNT, FASTVAR, CONST, NOARG). Row a0 = operator selector and count, a1 = the object’s fast slot, a2 = the attribute name.
Stack:
[..., v0 .. v_{n-1}] -> [...]. Read the object from its slot, reduce obj.attr in place with the count values left to right, store it back; pushes nothing. Hot: prologue only, tail-calling the body the elector slot holds, which guards through the field slot and reads, computes, and stores through its location; an empty elector slot or an ungated site takes the electing function, and the generic path runskos_attr_inplace_cachedthrough the field slot.Compiler form: The lowered form of VAR_ATTR_INPLACE.
Implementation:
koskari/lib/opcode/FAST_ATTR_INPLACE.c
KOS_OP_ITEM_STORE_FAST
Style: FASTVAR (the value’s slot).
Stack:
[..., obj, key] -> [...]. Set obj[key] = value with the object on the stack, the key on the stack and the value read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_STORE_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_STORE_FAST.c
KOS_OP_ITEM_CONST_STORE_FAST
Style: EXTRA (CONST, FASTVAR, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key a pool constant and the value read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_CONST_STORE_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_CONST_STORE_FAST.c
KOS_OP_ITEM_FAST
Style: FASTVAR (the key’s slot).
Stack:
[..., obj] -> [..., value]. Get obj[key] with the object on the stack and the key read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST.c
KOS_OP_ITEM_FAST_CLEAR
Style: FASTVAR (the key’s slot).
Stack:
[..., obj] -> [...]. Delete obj[key] with the object on the stack and the key read from a fast slot.Compiler form: The lowering of ITEM_VAR_CLEAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_CLEAR.c
KOS_OP_ITEM_FAST_TAKE
Style: FASTVAR (the key’s slot).
Stack:
[..., obj] -> [..., value]. Get obj[key], delete it, and push the value with the object on the stack and the key read from a fast slot.Compiler form: The lowering of ITEM_VAR_TAKE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_TAKE.c
KOS_OP_ITEM_FAST_REF
Style: FASTVAR (the key’s slot).
Stack:
[..., obj] -> [..., value]. Push an ItemRef over obj[key] with the object on the stack and the key read from a fast slot.Compiler form: The lowering of ITEM_VAR_REF: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_REF.c
KOS_OP_ITEM_FAST_STORE
Style: FASTVAR (the key’s slot).
Stack:
[..., obj, value] -> [...]. Set obj[key] = value with the object on the stack, the key read from a fast slot and the value on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_VAR_STORE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_STORE.c
KOS_OP_ITEM_FAST_STORE_CONST
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key read from a fast slot and the value a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_VAR_STORE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_STORE_CONST.c
KOS_OP_ITEM_FAST_STORE_FAST
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key read from a fast slot and the value read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_VAR_STORE_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_STORE_FAST.c
KOS_OP_ITEM_FAST_INPLACE
Style: EXTRA (OPCOUNT, FASTVAR, NOARG, NOARG).
Stack:
[..., obj, v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object on the stack and the key read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_VAR_INPLACE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_INPLACE.c
KOS_OP_ITEM_FAST_INPLACE_CONST
Style: EXTRA (OPERAND, FASTVAR, CONST, NOARG).
Stack:
[..., obj] -> [...]. Reduce obj[key] in place with the pool constant and store it back with the object on the stack and the key read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of ITEM_VAR_INPLACE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/ITEM_FAST_INPLACE_CONST.c
KOS_OP_FAST_ITEM
Style: FASTVAR (the object’s slot).
Stack:
[..., key] -> [..., value]. Get obj[key] with the object read from a fast slot and the key on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM.c
KOS_OP_FAST_ITEM_CLEAR
Style: FASTVAR (the object’s slot).
Stack:
[..., key] -> [...]. Delete obj[key] with the object read from a fast slot and the key on the stack.Compiler form: The lowering of VAR_ITEM_CLEAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CLEAR.c
KOS_OP_FAST_ITEM_TAKE
Style: FASTVAR (the object’s slot).
Stack:
[..., key] -> [..., value]. Get obj[key], delete it, and push the value with the object read from a fast slot and the key on the stack.Compiler form: The lowering of VAR_ITEM_TAKE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_TAKE.c
KOS_OP_FAST_ITEM_REF
Style: FASTVAR (the object’s slot).
Stack:
[..., key] -> [..., value]. Push an ItemRef over obj[key] with the object read from a fast slot and the key on the stack.Compiler form: The lowering of VAR_ITEM_REF: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_REF.c
KOS_OP_FAST_ITEM_STORE
Style: FASTVAR (the object’s slot).
Stack:
[..., key, value] -> [...]. Set obj[key] = value with the object read from a fast slot, the key on the stack and the value on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_STORE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_STORE.c
KOS_OP_FAST_ITEM_STORE_CONST
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[..., key] -> [...]. Set obj[key] = value with the object read from a fast slot, the key on the stack and the value a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_STORE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_STORE_CONST.c
KOS_OP_FAST_ITEM_STORE_FAST
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack:
[..., key] -> [...]. Set obj[key] = value with the object read from a fast slot, the key on the stack and the value read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_STORE_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_STORE_FAST.c
KOS_OP_FAST_ITEM_INPLACE
Style: EXTRA (OPCOUNT, FASTVAR, NOARG, NOARG).
Stack:
[..., key, v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object read from a fast slot and the key on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_INPLACE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_INPLACE.c
KOS_OP_FAST_ITEM_INPLACE_CONST
Style: EXTRA (OPERAND, FASTVAR, CONST, NOARG).
Stack:
[..., key] -> [...]. Reduce obj[key] in place with the pool constant and store it back with the object read from a fast slot and the key on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_INPLACE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_INPLACE_CONST.c
KOS_OP_FAST_ITEM_CONST
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key] with the object read from a fast slot and the key a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST.c
KOS_OP_FAST_ITEM_CONST_CLEAR
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack: No stack effect. Delete obj[key] with the object read from a fast slot and the key a pool constant.
Compiler form: The lowering of VAR_ITEM_CONST_CLEAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_CLEAR.c
KOS_OP_FAST_ITEM_CONST_TAKE
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key], delete it, and push the value with the object read from a fast slot and the key a pool constant.Compiler form: The lowering of VAR_ITEM_CONST_TAKE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_TAKE.c
KOS_OP_FAST_ITEM_CONST_REF
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[...] -> [..., value]. Push an ItemRef over obj[key] with the object read from a fast slot and the key a pool constant.Compiler form: The lowering of VAR_ITEM_CONST_REF: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_REF.c
KOS_OP_FAST_ITEM_CONST_STORE
Style: EXTRA (FASTVAR, CONST, NOARG, NOARG).
Stack:
[..., value] -> [...]. Set obj[key] = value with the object read from a fast slot, the key a pool constant and the value on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_CONST_STORE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_STORE.c
KOS_OP_FAST_ITEM_CONST_STORE_CONST
Style: EXTRA (FASTVAR, CONST, CONST, NOARG).
Stack: No stack effect. Set obj[key] = value with the object read from a fast slot, the key a pool constant and the value a pool constant.
Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_CONST_STORE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_STORE_CONST.c
KOS_OP_FAST_ITEM_CONST_STORE_FAST
Style: EXTRA (FASTVAR, CONST, FASTVAR, NOARG).
Stack: No stack effect. Set obj[key] = value with the object read from a fast slot, the key a pool constant and the value read from a fast slot.
Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_CONST_STORE_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_STORE_FAST.c
KOS_OP_FAST_ITEM_CONST_INPLACE
Style: EXTRA (OPCOUNT, FASTVAR, CONST, NOARG).
Stack:
[..., v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object read from a fast slot and the key a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_CONST_INPLACE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_INPLACE.c
KOS_OP_FAST_ITEM_CONST_INPLACE_CONST
Style: EXTRA (OPERAND, FASTVAR, CONST, CONST).
Stack: No stack effect. Reduce obj[key] in place with the pool constant and store it back with the object read from a fast slot and the key a pool constant.
Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_CONST_INPLACE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_CONST_INPLACE_CONST.c
KOS_OP_FAST_ITEM_FAST
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key] with the object read from a fast slot and the key read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST.c
KOS_OP_FAST_ITEM_FAST_CLEAR
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack: No stack effect. Delete obj[key] with the object read from a fast slot and the key read from a fast slot.
Compiler form: The lowering of VAR_ITEM_VAR_CLEAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_CLEAR.c
KOS_OP_FAST_ITEM_FAST_TAKE
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack:
[...] -> [..., value]. Get obj[key], delete it, and push the value with the object read from a fast slot and the key read from a fast slot.Compiler form: The lowering of VAR_ITEM_VAR_TAKE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_TAKE.c
KOS_OP_FAST_ITEM_FAST_REF
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack:
[...] -> [..., value]. Push an ItemRef over obj[key] with the object read from a fast slot and the key read from a fast slot.Compiler form: The lowering of VAR_ITEM_VAR_REF: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_REF.c
KOS_OP_FAST_ITEM_FAST_STORE
Style: EXTRA (FASTVAR, FASTVAR, NOARG, NOARG).
Stack:
[..., value] -> [...]. Set obj[key] = value with the object read from a fast slot, the key read from a fast slot and the value on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_VAR_STORE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_STORE.c
KOS_OP_FAST_ITEM_FAST_STORE_CONST
Style: EXTRA (FASTVAR, FASTVAR, CONST, NOARG).
Stack: No stack effect. Set obj[key] = value with the object read from a fast slot, the key read from a fast slot and the value a pool constant.
Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_VAR_STORE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_STORE_CONST.c
KOS_OP_FAST_ITEM_FAST_STORE_FAST
Style: EXTRA (FASTVAR, FASTVAR, FASTVAR, NOARG).
Stack: No stack effect. Set obj[key] = value with the object read from a fast slot, the key read from a fast slot and the value read from a fast slot.
Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_VAR_STORE_VAR: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_STORE_FAST.c
KOS_OP_FAST_ITEM_FAST_INPLACE
Style: EXTRA (OPCOUNT, FASTVAR, FASTVAR, NOARG).
Stack:
[..., v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object read from a fast slot and the key read from a fast slot.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_VAR_INPLACE: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_INPLACE.c
KOS_OP_FAST_ITEM_FAST_INPLACE_CONST
Style: EXTRA (OPERAND, FASTVAR, FASTVAR, CONST).
Stack: No stack effect. Reduce obj[key] in place with the pool constant and store it back with the object read from a fast slot and the key read from a fast slot.
Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: The lowering of VAR_ITEM_VAR_INPLACE_CONST: every named operand has a fast slot.
Implementation:
koskari/lib/opcode/FAST_ITEM_FAST_INPLACE_CONST.c
14. Attributes
KOS_OP_ATTR
Style: CONST. Arg = constant pool index of attribute name (post-compile).
Stack:
[..., obj] -> [..., value]. Get attribute; the value replaces the object.Invariants: TOS is the object. Name in constant pool.
Compiler form: Pre-compile arg = attribute name (string); post-compile arg = pool index.
Example: Get obj.name. Pool: 0 = “name”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘obj’) |
stack: […, obj] |
1 |
ATTR |
1 |
1 (‘name’) |
stack: […, obj, value] |
2 |
RETURN |
1 |
1 |
KOS_OP_ATTR_STORE
Style: CONST. Arg = constant pool index of attribute name.
Stack:
[..., obj, value] -> [...]. Set attribute on obj; pop both.Invariants: Below TOS is object; name in pool.
Example: Set obj.x = TOS. Pool: 0 = “x”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘obj’) |
stack: […, obj] |
1 |
CONST |
1 |
1 (10) |
stack: […, obj, 10] |
2 |
ATTR_STORE |
2 |
2 (‘x’) |
obj.x = 10; stack: […, obj] |
KOS_OP_ATTR_CLEAR
Style: CONST. Arg = constant pool index of attribute name.
Stack:
[..., obj] -> [...]. Delete attribute.Invariants: TOS is the object.
Example: Delete obj.attr. Pool: 0 = “attr”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘obj’) |
stack: […, obj] |
1 |
ATTR_CLEAR |
1 |
1 (‘attr’) |
del obj.attr |
KOS_OP_ATTR_TAKE
Style: CONST. Arg = constant pool index of attribute name.
Stack:
[..., obj] -> [..., value]. Get attribute, delete it, push value. Errors if attribute missing.Invariants: TOS is the object.
Compiler form: Emitted by compile/take-attr when OBJ is not a symbol.
Example: Take obj.attr. Pool: 0 = “attr”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘obj’) |
stack: […, obj] |
1 |
ATTR_TAKE |
1 |
1 (‘attr’) |
take obj.attr; stack: […, value] |
KOS_OP_ATTR_REF
Style: CONST. Arg = constant pool index of attribute name.
Stack:
[..., obj] -> [..., obj, attr_ref]. Push attribute reference.Invariants: TOS is the object.
Example: Push reference for obj.prop. Pool: 0 = “prop”.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘obj’) |
stack: […, obj] |
1 |
ATTR_REF |
1 |
1 (‘prop’) |
stack: […, obj, attr_ref] |
KOS_OP_ATTR_INPLACE
Style: EXTRA (OPCOUNT, CONST, NOARG, NOARG). Row a0 = operator selector and count, a1 = the attribute name.
Stack:
[..., obj, v0 .. v_{n-1}] -> [...]. Reduce obj.attr in place with the count values left to right, store it back, drop the object and the values; pushes nothing (the special appends CONST None). Cold: the operator switch lives in the sharedkos_inplace_reduce.Compiler form: Emitted by
compile/inplace-attrwhen OBJ is an expression.Implementation:
koskari/lib/opcode/ATTR_INPLACE.c
15. Items
The item rows are named by a three-position grammar: the leading marker names the object’s origin, ITEM is followed by the key’s, and a STORE or INPLACE verb by its value’s. An unmarked operand rides the stack; CONST is a pool constant, VAR a name resolved in the frame namespace (section 12), FAST a fast slot (section 13). FAST_ITEM_CONST_STORE_FAST is a fast object, a constant key, and a fast value; ITEM_VAR_STORE is a stack object, a named key, and a stack value. The row’s EXTRA fields follow name order, skipping stack operands; a row with one named operand takes that operand’s plain style. The stack order of the operands a row reads is object, key, value.
Every combination of stack and slot object, stack, constant, and slot key, and stack, constant, and slot value exists for ITEM, CLEAR, TAKE, REF, and STORE; the in-place rows take their operand from the stack or the pool, as every other INPLACE row does. A VAR row is the twin of a FAST row for a name with no fast slot; the lowering is all or nothing per row.
The ITEM, STORE, and INPLACE rows of the stack tier and the FAST tier
carry one KOS_CACHE_ITEM slot each. A handler fetches its operands by
origin and calls kos_item_load, kos_item_store, or
kos_item_inplace (eval/eval_item.c), which on the site’s first
execution elects a body for the container kind it sees: for a load an
exact list or tuple under an exact int key or an exact dict under any
key, for a store or an in-place reduce an exact list under an exact
int key or an exact dict, since a tuple takes no store. The body
guards the kind on every execution and reads or writes the container
directly; an index outside the sequence or a key the dict lacks runs
the object protocol for that execution, so IndexError and KeyError
keep their messages, and eight guard misses demote the site to the
protocol until the protocol’s own count wraps and the site re-elects.
A dict body that hashed the key and cannot finish keeps its hold on
the object and key and hands it to the protocol path, since the hash
may have rebound the slot a handler peeked. The in-place bodies are
one per operator for int and float cells plus the str body for +,
find the cell inside the body, and offer the cell’s value as the
result’s home under the in-place result rule. CLEAR, TAKE, and REF
run the object protocol through kos_item_clear, kos_item_take, and
kos_item_ref, which hold the operands across the call.
The compiler emits the plain stack row after the object, the key, and the value, and the compress pipeline folds the run of feeders directly ahead of the row, which in stack order is the value, then the key, then the object; a CONST in the object position never folds. A special shapes its emission only where a non-feeder operand would sit between a named operand and the row: a symbol object under a computed key names the object, and a computed value behind a symbol object or a feeder key names what it can.
Example: (set-item d "k" 42) in a function body, d a local.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
FAST_ITEM_CONST_STORE_CONST |
0 |
(fast 0 (d), c#0 (‘k’), c#1 (42), 0) |
d[‘k’] = 42; no stack effect |
KOS_OP_ITEM
Style: NOARG.
Stack:
[..., obj, key] -> [..., value]. Get obj[key] with the object on the stack and the key on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Emitted by
compile/item; the compress pipeline folds the run of feeders (bare VAR and CONST loads) ahead of it into the rows that name them.Implementation:
koskari/lib/opcode/ITEM.c
KOS_OP_ITEM_CLEAR
Style: NOARG.
Stack:
[..., obj, key] -> [...]. Delete obj[key] with the object on the stack and the key on the stack.Compiler form: Emitted by
compile/del-item; the compress pipeline folds the run of feeders (bare VAR and CONST loads) ahead of it into the rows that name them.Implementation:
koskari/lib/opcode/ITEM_CLEAR.c
KOS_OP_ITEM_TAKE
Style: NOARG.
Stack:
[..., obj, key] -> [..., value]. Get obj[key], delete it, and push the value with the object on the stack and the key on the stack.Compiler form: Emitted by
compile/take-item; the compress pipeline folds the run of feeders (bare VAR and CONST loads) ahead of it into the rows that name them.Implementation:
koskari/lib/opcode/ITEM_TAKE.c
KOS_OP_ITEM_REF
Style: NOARG.
Stack:
[..., obj, key] -> [..., value]. Push an ItemRef over obj[key] with the object on the stack and the key on the stack.Compiler form: Emitted by
compile/ref-item; the compress pipeline folds the run of feeders (bare VAR and CONST loads) ahead of it into the rows that name them.Implementation:
koskari/lib/opcode/ITEM_REF.c
KOS_OP_ITEM_STORE
Style: NOARG.
Stack:
[..., obj, key, value] -> [...]. Set obj[key] = value with the object on the stack, the key on the stack and the value on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Emitted by
compile/set-item; the compress pipeline folds the run of feeders (bare VAR and CONST loads) ahead of it into the rows that name them.Implementation:
koskari/lib/opcode/ITEM_STORE.c
KOS_OP_ITEM_STORE_CONST
Style: CONST (the value).
Stack:
[..., obj, key] -> [...]. Set obj[key] = value with the object on the stack, the key on the stack and the value a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Folded by the compress pipeline from
CONST value, ITEM_STORE.Implementation:
koskari/lib/opcode/ITEM_STORE_CONST.c
KOS_OP_ITEM_INPLACE
Style: OPCOUNT (operator selector, value count).
Stack:
[..., obj, key, v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object on the stack and the key on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Emitted by
compile/inplace-item; the compress pipeline folds the run of feeders (bare VAR and CONST loads) ahead of it into the rows that name them.Implementation:
koskari/lib/opcode/ITEM_INPLACE.c
KOS_OP_ITEM_INPLACE_CONST
Style: EXTRA (OPERAND, CONST, NOARG, NOARG).
Stack:
[..., obj, key] -> [...]. Reduce obj[key] in place with the pool constant and store it back with the object on the stack and the key on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Folded by the compress pipeline from
CONST rhs, ITEM_INPLACEat a count of one, or fromCONST rhsahead of the shaped ITEM_INPLACE.Implementation:
koskari/lib/opcode/ITEM_INPLACE_CONST.c
KOS_OP_ITEM_CONST
Style: CONST (the key).
Stack:
[..., obj] -> [..., value]. Get obj[key] with the object on the stack and the key a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Folded by the compress pipeline from
CONST key, ITEM.Implementation:
koskari/lib/opcode/ITEM_CONST.c
KOS_OP_ITEM_CONST_CLEAR
Style: CONST (the key).
Stack:
[..., obj] -> [...]. Delete obj[key] with the object on the stack and the key a pool constant.Compiler form: Folded by the compress pipeline from
CONST key, ITEM_CLEAR.Implementation:
koskari/lib/opcode/ITEM_CONST_CLEAR.c
KOS_OP_ITEM_CONST_TAKE
Style: CONST (the key).
Stack:
[..., obj] -> [..., value]. Get obj[key], delete it, and push the value with the object on the stack and the key a pool constant.Compiler form: Folded by the compress pipeline from
CONST key, ITEM_TAKE.Implementation:
koskari/lib/opcode/ITEM_CONST_TAKE.c
KOS_OP_ITEM_CONST_REF
Style: CONST (the key).
Stack:
[..., obj] -> [..., value]. Push an ItemRef over obj[key] with the object on the stack and the key a pool constant.Compiler form: Folded by the compress pipeline from
CONST key, ITEM_REF.Implementation:
koskari/lib/opcode/ITEM_CONST_REF.c
KOS_OP_ITEM_CONST_STORE
Style: CONST (the key).
Stack:
[..., obj, value] -> [...]. Set obj[key] = value with the object on the stack, the key a pool constant and the value on the stack.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Shaped by
compile/set-itemwhen OBJ is a symbol or KEY is a feeder and a value is not, so the fold could not reach the named operands.Implementation:
koskari/lib/opcode/ITEM_CONST_STORE.c
KOS_OP_ITEM_CONST_STORE_CONST
Style: EXTRA (CONST, CONST, NOARG, NOARG).
Stack:
[..., obj] -> [...]. Set obj[key] = value with the object on the stack, the key a pool constant and the value a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Folded by the compress pipeline from
CONST key, CONST value, ITEM_STORE, or fromCONST valueahead of the shaped ITEM_CONST_STORE.Implementation:
koskari/lib/opcode/ITEM_CONST_STORE_CONST.c
KOS_OP_ITEM_CONST_INPLACE
Style: EXTRA (OPCOUNT, CONST, NOARG, NOARG).
Stack:
[..., obj, v0 .. v_{n-1}] -> [...]. Reduce obj[key] in place with the count values left to right and store it back with the object on the stack and the key a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Shaped by
compile/inplace-itemwhen OBJ is a symbol or KEY is a feeder and a value is not, so the fold could not reach the named operands.Implementation:
koskari/lib/opcode/ITEM_CONST_INPLACE.c
KOS_OP_ITEM_CONST_INPLACE_CONST
Style: EXTRA (OPERAND, CONST, CONST, NOARG).
Stack:
[..., obj] -> [...]. Reduce obj[key] in place with the pool constant and store it back with the object on the stack and the key a pool constant.Cache: one KOS_CACHE_ITEM slot; the site elects a body for the container kind it first sees through the shared helper in
eval/eval_item.c(see section 15).Compiler form: Folded by the compress pipeline from
CONST key, CONST rhs, ITEM_INPLACEat a count of one, or fromCONST rhsahead of the shaped ITEM_CONST_INPLACE.Implementation:
koskari/lib/opcode/ITEM_CONST_INPLACE_CONST.c
15.1 Reference dereference
KOS_OP_DEREF
Style: NOARG.
Stack:
[..., ref] -> [..., value]. Pop one value (a Ref with a deref method). Callref.deref(), push result. Raises TypeError if TOS has no deref method.Use-case: Fast path for dereferencing a mutable reference. Used by the
(deref EXPR)special form.
Example: Dereference a ref. For (deref r) where r holds a Ref: VAR (or FAST) loads r, DEREF calls ref.deref().
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
VAR |
0 |
0 (‘r’) |
stack: […, ref] |
1 |
DEREF |
0 |
0 |
stack: […, value] |
16. Argument production
KOS_OP_BUILD_ARGS
Style: COUNT. Arg = number of positional arguments.
Stack:
[..., v_0, ..., v_{n-1}] -> [..., tuple]. Pop n elements and push a tuple of them.Example: Build empty args. Covered by
tests/lib/opcode/test_arg_opcodes.py.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
BUILD_ARGS |
0 |
0 |
stack: […, ()] |
1 |
RETURN |
1 |
1 |
KOS_OP_BUILD_FUNCTION
Style: EXTRA (
CONST,CONST,NOARG,NOARG). Instruction arg = index into the code object’s extra table; that row holdsa0= constant pool index of the keyword-defaults names tuple anda1= constant pool index of the annotation names tuple. Either or both may be the empty tuple, meaning no values of that kind on the stack.Stack:
[..., ann_1, ..., ann_M, def_1, ..., def_N, fspec] -> [..., function], where N = len(defaults names tuple) and M = len(annotation names tuple); either may be 0. The VM pops fspec, then (when N > 0) pops N values into a keyword-defaults dict keyed by the defaults names tuple, then (when M > 0) pops M more values into an annotations dict keyed by the annotation names tuple, and builds the function from the spec against the current frame namespace. The annotations dict becomes the function’s creation-time annotations: values are real objects, except str values, which remain forward references resolved lazily on first__annotations__/__signature__access.Invariants: Both extra-row fields must be constant-pool tuples; the stack must hold M + N values below fspec, with annotation values below default values.
Compiler form: Pre-compile extra operand is a 4-tuple
(defnames_tuple, annotation_names_tuple, 0, 0);NOARGslots are ignored by the assembler. The annotation names tuple is the annotated parameter names in order, followed by"return"when a return annotation is present.
Example: Build annotated function with one keyword default, as for (lambda [(a :: int value: 9)] a). Pool: 0 = int, 1 = 9, 2 = function_spec; extra row: (("a",), ("a",), 0, 0). Covered by tests/lib/opcode/test_build_function.py.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (int) |
annotation value; stack: […, int] |
1 |
CONST |
1 |
1 (9) |
default value; stack: […, int, 9] |
2 |
CONST |
2 |
2 (fspec) |
stack: […, int, 9, fspec] |
3 |
BUILD_FUNCTION |
0 |
0 ((“a”,), (“a”,), …) |
stack: […, function] |
4 |
RETURN |
1 |
1 |
Un-annotated, no-defaults form: extra row ((), (), 0, 0); only fspec is popped.
KOS_OP_BUILD_KWDS
Style: PAIR_COUNT. Arg = number of keyword pairs.
Stack:
[..., k_0, v_0, ..., k_{n-1}, v_{n-1}] -> [..., dict]. Pop 2*opa elements as key,value pairs and push a dict.
KOS_OP_BUILD_KWDS_NAMES
Style: CONST. Arg = constant pool index of names tuple.
Stack:
[..., v_0, ..., v_{n-1}] -> [..., dict]. Pop n values, map names[i] -> value[i], push dict. Names tuple from constant pool; values from stack (val_0 deepest, val_{n-1} at TOS).
KOS_OP_BUILD_LIST
Style: COUNT. Arg = number of elements.
Stack:
[..., v_0, ..., v_{n-1}] -> [..., list]. Pop n elements into a new list and push it. Empty (arg 0) pushes[].Compiler form:
compile/#listfor a leading/all dynamic run (collections.py).
KOS_OP_BUILD_LIST_CONST
Style: CONST. Arg = constant pool index of a sequence (typically a pooled constant tuple).
Stack:
[...] -> [..., list]. Build a fresh list from the pooled sequence (PySequence_List) and push it; each eval mints a new list, never aliasing the immutable pool value.Compiler form:
compile/#listall-constant body, or the seed of a list whose first run is constant.
KOS_OP_VAR_LIST_APPEND
Style: VAR. Arg = variable name (may lower to FAST_LIST_APPEND).
Stack:
[..., value] -> [...]. Append TOS to the list bound to the named variable, in place. Used bycompile/#list-appendon a symbol binding.
KOS_OP_FAST_LIST_APPEND
Style: FASTVAR. Arg = frame slot index.
Stack:
[..., value] -> [...]. Fast-slot form of VAR_LIST_APPEND.
KOS_OP_BUILD_LIST_APPEND
Style: COUNT. Arg = number of values to append.
Stack:
[..., list, v_0, ..., v_{n-1}] -> [..., list]. Append the top n values to the list at depth n, in place; pop the values; leave the list. TypeError when the list slot is not a list. (Widened from the former NOARG append-one;compile/#list-appendon a list expression emits count 1.)Compiler form:
compile/#listdynamic tail run of k;compile/#list-appendlist-expression path (count 1).
KOS_OP_BUILD_LIST_APPEND_CONST
Style: CONST. Arg = constant pool index of a single value.
Stack:
[..., list] -> [..., list]. Append the pooled value to the TOS list in place. TypeError when TOS is not a list.Compiler form:
compile/#listtail constant run of length 1.
KOS_OP_BUILD_LIST_EXTEND
Style: NOARG.
Stack:
[..., list, iterable] -> [..., list]. Extend the list in place from the TOS iterable (PySequence_InPlaceConcat, so any iterable the list API accepts); pop the iterable; leave the list. TypeError when the list slot is not a list.Compiler form:
compile/#list*:splat segment.
KOS_OP_BUILD_LIST_EXTEND_CONST
Style: CONST. Arg = constant pool index of a sequence (typically a pooled constant tuple).
Stack:
[..., list] -> [..., list]. Extend the TOS list in place from the pooled sequence (tuple fast path, general-iterable fallback). TypeError when TOS is not a list.Compiler form:
compile/#listtail constant run of length >= 2.
KOS_OP_COMBINE_ARGS
Style: COUNT. Arg = count of sequences to combine.
Stack:
[..., t_0, ..., t_{m-1}] -> [..., tuple]. Concatenate the m sequences (each via iteration) into a single tuple. Non-tuple values are converted with PySequence_Tuple when m == 1.
KOS_OP_COMBINE_KWDS
Style: COUNT. Arg = count of dicts to merge.
Stack:
[..., d_0, ..., d_{m-1}] -> [..., dict]. Merge the m dicts (later overwrites earlier on key clash) and push result.
17. Calls
KOS_OP_CALL
Style: COUNT. Arg = number of positional arguments.
Stack:
[..., callable, arg_1, ..., arg_n] -> [..., result]. KosExpression/KosFunction: new frame pushed, in-loop execution. Python callable: may suspend on awaitable.Execution model: Only the call result is ever auto-awaited: when a Python call returns a coroutine/awaitable, the VM awaits it (flattened) and pushes the final value. All other opcodes (CONST, loads, getattr, subscript, binary ops, yield-from results, etc.) push their value with no automatic await; use the AWAIT opcode to await explicitly.
Invariants: Stack has at least 1 + arg elements. See execution-invariants for in-loop flattening.
Example: Call with 1 argument. Pool: 0 = fn, 1 = 42.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (fn) |
stack: […, callable] |
1 |
CONST |
1 |
1 (42) |
stack: […, callable, 42] |
2 |
CALL |
1 |
1 |
pop callable + 1 arg; push result. stack: […, result] |
3 |
RETURN |
1 |
1 |
KOS_OP_CALL_NAMES
Style: COUNT. Arg = N (number of positional arguments).
Stack:
[..., callable, pos_0, ..., pos_{N-1}, val_0, ..., val_{M-1}, names_tuple] -> [..., result]. TOS = names_tuple (tuple of M keyword names); below it the M keyword values in the same order as names; below that the N positional args; then callable. TailPtr for callable + args + kwnames; validate names tuple; kos_callable_vcall; DropNoErr. No tuple or dict allocation.Invariants: names_tuple must be a tuple; stack must have 1 + N + M + 1 elements (callable + N positionals + M keyword values + names).
Example: Call with 1 positional and 1 keyword (x=42). Pool: 0 = fn, 1 = 10, 2 = 42, 3 = (“x”,).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (fn) |
stack: […, callable] |
1 |
CONST |
1 |
1 (10) |
stack: […, callable, 10] |
2 |
CONST |
2 |
2 (42) |
stack: […, callable, 10, 42] |
3 |
CONST |
3 |
3 (names) |
stack: […, callable, 10, 42, names] |
4 |
CALL_NAMES |
1 |
1 |
stack: […, result] |
5 |
RETURN |
1 |
1 |
KOS_OP_CALL_STAR
Style: STAR. Arg = bitflags (1 = has *args, 2 = has **kwargs).
Stack:
[..., callable, pos, kwd]with kwd at TOS. pos = *args (tuple or iterable); kwd = **kwargs (dict). Pop per opa: both (opa & 3 == 3): pop 3; **kwargs only (opa & 2): pop 2, pos = (); *args only (opa & 1): pop 2, kwd = NULL; neither: pop 1, pos = (), kwd = NULL. Ensure pos is tuple (PySequence_Tuple if needed). Call via kos_callable_call(ctx, out_ev, callable, pos, kwd).Invariants: Stack height per opa; pos converted to tuple when *args present.
Example: Call with *args and **kwargs. Pool: 0 = fn, 1 = (1,2), 2 = {“x”: 3}.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (fn) |
stack: […, callable] |
1 |
CONST |
1 |
1 (pos) |
stack: […, callable, pos] |
2 |
CONST |
2 |
2 (kwd) |
stack: […, callable, pos, kwd] |
3 |
CALL_STAR |
3 |
3 (bits) |
stack: […, result] |
4 |
RETURN |
1 |
1 |
KOS_OP_CALL_VAR
Style: EXTRA. Schema: VAR (name cpool idx), COUNT (npos), NOARG, NOARG.
Stack:
[..., pos_0, ..., pos_{N-1}] -> [..., result]. The callee is read from the frame namespace by name and is not on the stack. A Koskari callable runs in the evaluator with the arguments taken from the stack; any other callable is called with them and its result pushed, awaited when awaitable.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_FAST
Style: EXTRA. Schema: FASTVAR (slot index), COUNT (npos), NOARG, NOARG.
Stack: Same as CALL_VAR. Callable is loaded from fast local slot via
KosNamespace_FastDeref; not on stack.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_VAR_NAMES
Style: EXTRA. Schema: VAR (name cpool idx), CONST (kw names tuple cpool idx), COUNT (npos), NOARG.
Stack:
[..., pos_0, ..., pos_{N-1}, kwd_val_0, ..., kwd_val_{M-1}] -> [..., result]. Callable from namespace by name; kw names tuple from constant pool. Same call semantics as CALL_NAMES.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_FAST_NAMES
Style: EXTRA. Schema: FASTVAR (slot index), CONST (kw names tuple cpool idx), COUNT (npos), NOARG.
Stack: Same as CALL_VAR_NAMES. Callable from fast slot via
KosNamespace_FastDeref.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_VAR_STAR
Style: EXTRA. Schema: VAR (name cpool idx), STAR (bitflags: 1 = *args, 2 = **kwargs), NOARG, NOARG.
Stack: Same as CALL_STAR minus callable.
[..., pos, kwd]or subsets per flags. The callee is read from the frame namespace by name. The operands present are popped per the flags,posis made a tuple, and the callee is called with them.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_FAST_STAR
Style: EXTRA. Schema: FASTVAR (slot index), STAR (bitflags), NOARG, NOARG.
Stack: Same as CALL_VAR_STAR. Callable from fast slot via
KosNamespace_FastDeref.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_ATTR
Style: EXTRA. Schema: CONST (attr name), COUNT (npos), NOARG, NOARG.
Stack:
[..., obj, arg_0, ..., arg_{N-1}] -> [..., result]. Attr name from constant pool (EXTRA row).obj.nameis resolved as an attribute read would resolve it, then invoked. An unbound plain function found on the class is called asfn(obj, *args); a bound method, an instance-dict callable or a descriptor’s result is called ascallable(*args).Invariants: Stack has at least 1 + N elements (obj, N args). Resolved attribute must be callable or TypeError.
Receiver: the resolution decides whether
objis passed: an unbound plain function from the class gets it as the first argument; anything else is called with the arguments alone. A Koskari callable runs in the evaluator; any other callable is called and its result pushed, awaited when awaitable.
Example: "hello".upper() (0 args). Pool: 0 = “upper”, 1 = “hello”. EXTRA row 0: a0 = cpool index of “upper”, a1 = 0 (npos).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
1 |
1 (“hello”) |
stack: […, obj] |
1 |
CALL_ATTR |
0 |
0 (extra idx) |
resolve obj.upper; call; push result. stack: […, “HELLO”] |
2 |
RETURN |
1 |
1 |
Example: c.add_one(41) (1 arg, unbound method). Pool: 0 = “add_one”, 1 = c, 2 = 41. EXTRA row 0: a0 = cpool index of “add_one”, a1 = 1 (npos).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
1 |
1 (c) |
stack: […, obj] |
1 |
CONST |
2 |
2 (41) |
stack: […, obj, 41] |
2 |
CALL_ATTR |
0 |
0 (extra idx) |
resolve; call add_one(c, 41); push 42. stack: […, 42] |
3 |
RETURN |
1 |
1 |
KOS_OP_CALL_ATTR_NAMES
Style: EXTRA. Schema: CONST (attr name), CONST (kwarg names tuple), COUNT (npos), NOARG.
Stack:
[..., obj, pos_0, ..., pos_{N-1}, kwd_val_0, ..., kwd_val_{M-1}] -> [..., result].obj.nameresolves as CALL_ATTR describes; the call then proceeds like CALL_NAMES. The kwarg names tuple and attr name are in the constant pool (EXTRA row), not on the stack.Compiler form: Emitted by
compile/call-attrwhen the call has keyword arguments and no*:or**:.
KOS_OP_CALL_FAST_ATTR
Style: EXTRA. Schema: FASTVAR (slot index for
obj), CONST (attr name), COUNT (npos), NOARG.Stack:
[..., arg_0, ..., arg_{N-1}] -> [..., result]. Same resolution and invocation rules asKOS_OP_CALL_ATTR, butobjis not on the stack: it is read from the current frame’s fast slota0, so the frame must have fast locals. An unbound function found on the class receivesobjas its first argument; any other callable receives theNarguments alone.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_VAR_ATTR
Style: EXTRA. Schema: VAR (name cpool index for
obj), CONST (attr name), COUNT (npos), NOARG.Stack: Same as
KOS_OP_CALL_FAST_ATTR.objis read from the frame namespace by name.Behaviour: otherwise as
KOS_OP_CALL_FAST_ATTRandKOS_OP_CALL_ATTR: the same resolution, the same receiver rule, a Koskari callable run in the evaluator and any other called with its result pushed.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_FAST_ATTR_NAMES
Style: EXTRA. Schema: FASTVAR (slot index for obj), CONST (attr name), CONST (kwarg names tuple), COUNT (npos).
Stack:
[..., pos_0, ..., pos_{N-1}, kwd_val_0, ..., kwd_val_{M-1}] -> [..., result].objis read from fast slota0and is not on the stack, one fewer element than CALL_ATTR_NAMES. Resolution and the call proceed as CALL_ATTR_NAMES describes: an unbound function found on the class receivesobjfirst, any other callable the arguments alone.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_VAR_ATTR_NAMES
Style: EXTRA. Schema: VAR (name/cpool for obj), CONST (attr name), CONST (kwarg names tuple), COUNT (npos).
Stack: Same as CALL_FAST_ATTR_NAMES.
objis read from the frame namespace by name instead of a fast slot.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_ATTR_STAR
Style: EXTRA. Schema: CONST (attr name), COUNT (opa bitflags: 1 = has *args, 2 = has **kwargs), NOARG, NOARG.
Stack:
obj.name(*args, **kwargs). Stack layout per opa flags (bottom … TOS): opa=0 ->[obj]; opa=1 ->[obj, pos](pos = *args); opa=2 ->[obj, kwd](kwd = **kwargs); opa=3 ->[obj, pos, kwd]. Pop in reverse order (kwd then pos then obj when both star forms are present).posis made a tuple when it is another sequence.obj.nameresolves as CALL_ATTR describes;objis prepended to the positional tuple when the attribute is an unbound function, and the callee is called with the tuple and the keywords.Invariants: attr name in constant pool. opa bits: 1 = has *args, 2 = has **kwargs.
KOS_OP_CALL_VAR_ATTR_STAR
Style: EXTRA. Schema: VAR (name cpool index for
obj), CONST (attr name), COUNT (opa bitflags: 1 = has *args, 2 = has **kwargs), NOARG.Stack: Same semantics as
KOS_OP_CALL_ATTR_STAR, butobjis not on the stack; it is read from the frame namespace by name. Stack layout per opa (bottom … TOS): opa=0 ->[]; opa=1 ->[pos]; opa=2 ->[kwd]; opa=3 ->[pos, kwd]withkwdat TOS (same relative order as CALL_ATTR_STAR without the receiver). Pop order andopahandling matchKOS_OP_CALL_VAR_STARcombined with CALL_ATTR_STAR;obj.nameresolves as CALL_ATTR describes,objis prepended to the positional tuple when the attribute is an unbound function, and the callee is called with the tuple and the keywords.Invariants:
var_nameand attr name in constant pool; same opa bit meanings as CALL_ATTR_STAR.See also:
KOS_OP_CALL_VAR_ATTRfor the receiver read by name.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_CALL_FAST_ATTR_STAR
Style: EXTRA. Schema: FASTVAR (slot index for
obj), CONST (attr name), COUNT (opa bitflags), NOARG.Stack: Same stack layout and
opabehavior asKOS_OP_CALL_VAR_ATTR_STAR.objis read from fast slota0, so the frame must have fast locals. Pop, resolution and the call match CALL_ATTR_STAR.Invariants: Same opa and tuple/
posrules as CALL_ATTR_STAR; fast slot must be in range and bound.Compiler form: Not emitted by the compiler; available for manual bytecode construction.
KOS_OP_TAIL_CALL
Style: COUNT. Arg = number of positional arguments.
Stack: Same as CALL:
[..., callable, arg_1, ..., arg_n]. The arguments are taken off the stack before the callee is examined. A Koskari callable takes over the current frame; any other callable is called after the current frame is dropped, when it has a parent, and its result goes to the caller. Control then continues in the frame now on top, running any wind thunks on the way.Execution model: When the callable is a KosExpression or KosFunction, the VM replaces the current frame (tail install). For all other callable types, the opcode drops the current frame when parent exists, calls the callable, and pushes the result.
Invariants: Stack has at least 1 + arg elements. KosExpression allows no arguments (arg must be 0); otherwise TypeError.
Compiler form: Produced by the processor’s
promote_tail_callspass relabeling a tail-position CALL in function-body code; never emitted by a special.
Example: Tail call with 0 args (replace frame with callee). Pool: 0 = fn.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (fn) |
stack: […, callable] |
1 |
TAIL_CALL |
0 |
0 |
replace frame; run callee. stack: […,] (new frame) |
KOS_OP_TAIL_CALL_NAMES
Style: COUNT. Arg = N (number of positional arguments).
Stack: Same layout as CALL_NAMES:
[..., callable, pos_0, ..., pos_{N-1}, val_0, ..., val_{M-1}, names_tuple]. The arguments and the names tuple are taken off the stack before the callee is examined; the call then proceeds as TAIL_CALL describes, with the keywords bound by name.
KOS_OP_TAIL_CALL_STAR
Style: STAR. Arg = bitflags (1 = has *args, 2 = has **kwargs).
Stack: Same layout as CALL_STAR:
[..., callable, pos, kwd]. Pop order and the tuple coercion as CALL_STAR; the call then proceeds as TAIL_CALL describes, withposandkwdspread.
KOS_OP_TAIL_CALL_ATTR
Style: EXTRA. Schema: CONST (attr name), COUNT (npos), NOARG, NOARG. One cache slot (attr resolution).
Stack: Same layout as CALL_ATTR:
[..., obj, arg_0, ..., arg_{N-1}].obj.nameresolves as CALL_ATTR describes, then the call is made in tail position: a Koskari function takes over the caller’s frame rather than a new frame being pushed, and any other callable is called as TAIL_CALL describes.Compiler form: Produced by the processor’s
promote_tail_callspass relabeling a tail-position CALL_ATTR in function-body code; never emitted by a special.
KOS_OP_TAIL_CALL_ATTR_NAMES
Style: EXTRA. Schema: CONST (attr name), CONST (kwarg names tuple), COUNT (npos), NOARG. One cache slot.
Stack: Same layout as CALL_ATTR_NAMES. Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_ATTR_NAMES; never emitted by a special.
KOS_OP_TAIL_CALL_ATTR_STAR
Style: EXTRA. Schema: CONST (attr name), COUNT (opa bitflags: 1 = has *args, 2 = has **kwargs), NOARG, NOARG. One cache slot.
Stack: Same layout and pop order as CALL_ATTR_STAR; the call is a tail call, so the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_ATTR_STAR; never emitted by a special.
KOS_OP_TAIL_CALL_VAR
Style: EXTRA. Schema: VAR (name cpool idx), COUNT (npos), NOARG, NOARG.
Stack: Same layout as CALL_VAR:
[..., pos_0, ..., pos_{N-1}]; the callable is loaded from the frame namespace by name, not on the stack. Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.Compiler form: Promotion relabel of a tail-position CALL_VAR; convert_fast lowers it to TAIL_CALL_FAST when the name has a fast slot.
KOS_OP_TAIL_CALL_VAR_NAMES
Style: EXTRA. Schema: VAR (name), CONST (kwarg names tuple), COUNT (npos).
Stack: Same layout as CALL_VAR_NAMES. Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_VAR_NAMES; lowers to TAIL_CALL_FAST_NAMES.
KOS_OP_TAIL_CALL_VAR_STAR
Style: EXTRA. Schema: VAR (name), STAR (bitflags), NOARG, NOARG.
Stack: Same layout and pop order as CALL_VAR_STAR; the call is a tail call, so the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_VAR_STAR; lowers to TAIL_CALL_FAST_STAR.
KOS_OP_TAIL_CALL_VAR_ATTR
Style: EXTRA. Schema: VAR (name for obj), CONST (attr name), COUNT (npos), NOARG. One cache slot.
Stack: Same layout as CALL_VAR_ATTR: args only; obj is loaded from the frame namespace by name (owned deref, released on every path). Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_VAR_ATTR; lowers to TAIL_CALL_FAST_ATTR.
KOS_OP_TAIL_CALL_VAR_ATTR_NAMES
Style: EXTRA. Schema: VAR (name for obj), CONST (attr name), CONST (kwarg names tuple), COUNT (npos). One cache slot.
Stack: Same layout as CALL_VAR_ATTR_NAMES. Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_VAR_ATTR_NAMES; lowers to TAIL_CALL_FAST_ATTR_NAMES.
KOS_OP_TAIL_CALL_VAR_ATTR_STAR
Style: EXTRA. Schema: VAR (name for obj), CONST (attr name), COUNT (opa bitflags), NOARG. One cache slot.
Stack: Same layout and pop order as CALL_VAR_ATTR_STAR; the call is a tail call, so the caller’s frame is reused rather than a new frame pushed.
Compiler form: Promotion relabel of a tail-position CALL_VAR_ATTR_STAR; lowers to TAIL_CALL_FAST_ATTR_STAR.
KOS_OP_TAIL_CALL_FAST
Style: EXTRA. Schema: FASTVAR (slot index), COUNT (npos), NOARG, NOARG.
Stack: Same layout as CALL_FAST; the callable is loaded from the fast local slot (owned deref). Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Reached through promotion of CALL_VAR plus the fast lowering, or promotion of an already-lowered CALL_FAST; never emitted by a special.
KOS_OP_TAIL_CALL_FAST_NAMES
Style: EXTRA. Schema: FASTVAR (slot), CONST (kwarg names tuple), COUNT (npos).
Stack: Same layout as CALL_FAST_NAMES. Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Fast tier of TAIL_CALL_VAR_NAMES; see
KOS_OP_TAIL_CALL_FAST.
KOS_OP_TAIL_CALL_FAST_STAR
Style: EXTRA. Schema: FASTVAR (slot), STAR (bitflags), NOARG, NOARG.
Stack: Same layout and pop order as CALL_FAST_STAR; the call is a tail call, so the caller’s frame is reused rather than a new frame pushed.
Compiler form: Fast tier of TAIL_CALL_VAR_STAR; see
KOS_OP_TAIL_CALL_FAST.
KOS_OP_TAIL_CALL_FAST_ATTR
Style: EXTRA. Schema: FASTVAR (slot for obj), CONST (attr name), COUNT (npos), NOARG. One cache slot.
Stack: Same layout as CALL_FAST_ATTR: args only; obj is loaded from the fast local slot (owned deref, released on every path). Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Fast tier of TAIL_CALL_VAR_ATTR; see
KOS_OP_TAIL_CALL_FAST.
KOS_OP_TAIL_CALL_FAST_ATTR_NAMES
Style: EXTRA. Schema: FASTVAR (slot for obj), CONST (attr name), CONST (kwarg names tuple), COUNT (npos). One cache slot.
Stack: Same layout as CALL_FAST_ATTR_NAMES. Tail semantics as KOS_OP_TAIL_CALL_ATTR: the caller’s frame is reused rather than a new frame pushed.
Compiler form: Fast tier of TAIL_CALL_VAR_ATTR_NAMES; see
KOS_OP_TAIL_CALL_FAST.
KOS_OP_TAIL_CALL_FAST_ATTR_STAR
Style: EXTRA. Schema: FASTVAR (slot for obj), CONST (attr name), COUNT (opa bitflags), NOARG. One cache slot.
Stack: Same layout and pop order as CALL_FAST_ATTR_STAR; the call is a tail call, so the caller’s frame is reused rather than a new frame pushed.
Compiler form: Fast tier of TAIL_CALL_VAR_ATTR_STAR; see
KOS_OP_TAIL_CALL_FAST.
18. Block control
KOS_OP_PUSH_FOREACH
Style: NOARG. Argument unused; break target is derived at runtime from the extent table (
pop_pc + 1).Stack: Pops iterable (TOS); creates iterator; pushes the FOREACH node, which owns its segment. Region loop result starts unset. ITER_NEXT uses the node’s iterator. Break target =
extent.pop_pc + 1(instruction after the matching POP_FOREACH).Pushes: KOS_DYN_FOREACH (static extent KOS_EXT_FOREACH; node holds iterator and loop state).
Invariants: A KOS_EXT_FOREACH extent must exist at the PUSH_FOREACH PC; otherwise RuntimeError. Extent kind KOS_EXT_FOREACH.
Compiler form: Pre-compile arg = 0 (unused). Break target is not stored in the instruction; it is derived at runtime via
kos_extent_find(KOS_EXT_FOREACH)->ext->pop_pc + 1.
Example: for x in [1,2,3]: body. Stack at entry: […, iterable]. Pool: 0 = [1,2,3].
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 ([1,2,3]) |
stack: […, iterable] |
1 |
PUSH_FOREACH |
0 |
0 |
pop iterable; push FOREACH region; break_pc = pop_pc+1 from extent table |
2 |
ITER_NEXT |
6 |
6 (-> 6) |
next from region; else -> 6. stack: […, x] |
3 |
POP |
1 |
1 |
body: consume x |
4 |
JUMP |
2 |
2 (-> 2) |
loop back |
5 |
POP_FOREACH |
0 |
0 |
push loop result (None if unset) |
6 |
LABEL |
– |
– |
break / exhausted (= pop_pc+1) |
18.1 Context managers (with / dyn-with)
Context managers (with / dyn-with) at the language level: with, dyn-with. Summary below.
KOS_OP_PUSH_WITH
Style: CONST. Arg = constant pool index of binding name (symbol/string) or sentinel for no binding.
Stack before:
[..., mgr]. Stack after: body runs in a fresh operand segment.Behaviour: Pop
mgr; resolve and cache enter/exit; call enter (auto-await if needed); on success bind enter result if name given; push new segment; look up WITH extent at current PC, computeresume_pc = ext->pop_pc + 1; pushKOS_DYN_WITHwithresume_pcstored on the node. On enter failure, no node or block is installed; exception propagates.Pushes: KOS_DYN_WITH (single-shot: exits once on unwind or transfer, never re-entered). Node stores
resume_pc(instruction after POP_WITH) for use when exit swallows an exception.Invariants: Node owns one operand segment; stack restoration is structural (segment pop), not height-mark. A WITH extent must exist at the PUSH_WITH PC; otherwise RuntimeError.
KOS_OP_POP_WITH
Style: NOARG (argument unused in current
opcodes.incl).Behaviour: Store the body value on the node; call exit (no-exception form); auto-await if needed; pop the owned segment; pop dyn node; push the stored body value. When exit returns an awaitable: step via
kos_with_exit_start_await; on sync completion (r==0) callkos_complete_pending_with_exitto consume the exit result and push the body value; on suspend returnsEVAL_AWAIT(awaitable); on resume, revive callskos_complete_pending_with_exitso the with-expression value is the body’s (exit return is never left on stack). On exception unwind (via no-region path or dyn_pop_top_with): call exit(exc_info); if swallow then clear exception, pop block, pop node, pushNone, set frame PC toKosDynWith_RESUME_PC(node)(the instruction after POP_WITH), resume; else pop block, pop node, re-raise.Invariants: Top of chain must be KOS_DYN_WITH. With-expression value is the body’s value, or
Nonewhen exit swallowed an exception; exit return is used only for swallow logic and is never the value seen by RETURN.
KOS_OP_PUSH_DYN_WITH
Style: CONST. Arg = constant pool index of binding name or sentinel for no binding (same as PUSH_WITH).
Stack / behaviour: Same as PUSH_WITH except that the node is marked multi-shot (
KOS_DYN_WITH_SHOT_MULTI) and the DYN_WITH extent supplies the pcs. The node participates in continuation transfer plans (wind/unwind on non-local transfer).Pushes: KOS_DYN_WITH, multi-shot.
KOS_OP_POP_DYN_WITH
Style: NOARG.
Behaviour: Same as POP_WITH for normal and exception unwind. Pops the multi-shot KOS_DYN_WITH.
KOS_OP_PUSH_COLLECT
Style: CONST. Arg = constant pool index of NamespaceSpec.
Stack: Does not consume the stack. Loads NamespaceSpec from constant pool at arg, creates CollectorNamespace, installs as frame ns, pushes KOS_DYN_COLLECT, and owns an operand segment; the body runs in it; expression results (e.g. None from compile/define) stay in the block and are discarded on POP_COLLECT.
Pushes: KOS_DYN_COLLECT (static extent KOS_EXT_COLLECT; stores saved ns for restore on POP_COLLECT), with its owned segment for the body.
Invariants: Extent kind KOS_EXT_COLLECT. Frame namespace must be KosNamespace.
KOS_OP_POP_COLLECT
Style: NOARG. Argument unused.
Stack: Verifies dyn_top is KOS_DYN_COLLECT. Restores frame ns, drops the stack block (discarding body expression results), pops the dyn node, pushes the collected namespace onto the value stack.
[..., pos] -> [..., pos, ns].Invariants: Top of chain must be KOS_DYN_COLLECT.
KOS_OP_BUILD_CLASS
Style: NOARG. Argument unused.
Stack: Expects
[..., pos, ns]with TOS = ns, TOS-1 = pos. Pops ns, pos. pos = (name, bases) or (name, bases, metaclass). Builds the class viakos_build_class(namespace materialization, demand-wrap of slot-backed dunders, metaclass resolution – plaintypeby default – with__prepare__, merge, metaclass call); pushes resulting class.Compiler form: Build pos with BUILD_ARGS; use with_collector_namespace for PUSH_COLLECT/body/POP_COLLECT; then BUILD_CLASS. See compile/build-class.
Example: Empty class C. PUSH_COLLECT arg = constant pool index of nspec.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
0 (“C”) |
name |
1 |
CONST |
1 |
1 (()) |
bases |
2 |
BUILD_ARGS |
2 |
2 |
stack: […, pos] |
3 |
PUSH_COLLECT |
2 |
2 (nspec) |
push collect scope; nspec from cpool |
4 |
POP_COLLECT |
0 |
0 |
drop block; pop; push ns |
5 |
BUILD_CLASS |
0 |
0 |
metaclass(name,bases,dict); push cls |
6 |
RETURN |
1 |
1 |
KOS_OP_PUSH_LOOP
Style: NOARG. Argument unused; break target is derived at runtime from the extent table (
pop_pc + 1). Continue target = instruction immediately following PUSH_LOOP (i.e.CURRENT_PCafter the evaluator has advanced past the opcode).Stack: Pushes the LOOP node, which owns its segment. Break/continue use
break_pc(derived at runtime) andcontinue_pc(next instruction after PUSH_LOOP). Initializes node result toNone.Pushes: KOS_DYN_LOOP (static extent KOS_EXT_LOOP; with its own segment for the loop body).
Invariants: A KOS_EXT_LOOP extent must exist at the PUSH_LOOP PC; otherwise RuntimeError. Extent kind KOS_EXT_LOOP.
Compiler form: Pre-compile arg = 0 (unused). Break target is not stored in the instruction; it is derived at runtime via
kos_extent_find(KOS_EXT_LOOP)->ext->pop_pc + 1.
Example: while loop. Break target derived from extent table (pop_pc+1 = 6).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
PUSH_LOOP |
0 |
0 |
push LOOP region; break_pc = pop_pc+1 from extent table; continue_pc = 1 |
1 |
CONST |
0 |
0 (False) |
condition |
2 |
JUMP_FALSE |
5 |
5 (-> 5) |
exit loop if false; jumps to POP_LOOP |
3 |
… |
… |
… |
body |
4 |
JUMP |
1 |
1 (-> 1) |
continue (loop head) |
5 |
POP_LOOP |
0 |
0 |
|
6 |
LABEL |
– |
– |
break target (= pop_pc+1) |
KOS_OP_PUSH_NS
Style: EXTRA. Schema: CONST (cpool index of NamespaceSpec), CONST (cpool index of names tuple or None), NOARG, NOARG. Instruction
argis the extra-row index. Binding count islen(names)when names is a tuple, or0when names isNone.Constant pool: NSPEC and NAMES are loaded from the pool; they are not placed on the stack by preceding
CONSTopcodes.Stack: If
opa == 0, no stack operands for bindings. Ifopa > 0, stack is[..., val_0, ..., val_{opa-1}]with TOS = last value; names come from the extra row. The VM bindsnames[i]toval[i], then dropsopastack slots.Pushes: KOS_DYN_NS (static extent KOS_EXT_NS; owns its operand segment; the prior namespace returns on POP_NS when the enclosing node is revealed).
Invariants: Extent kind KOS_EXT_NS.
Example: Push namespace with no bound values (names = None). Operand row holds NSPEC and None; stack carries only the chain side effect until body runs.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
PUSH_NS |
0 |
extra row 0 (e.g. c# nspec, c# None) |
push NS region; chain: […, KosDynNs] |
1 |
… |
… |
… |
body |
2 |
POP_NS |
0 |
0 |
pop NS; restore previous namespace |
KOS_OP_PUSH_TRY
Style: LABEL. Handler targets in extent table.
Stack: Pushes TRY node and a KosSegment (like PUSH_LOOP). Exception dispatch clears the segment before jumping to the handler. POP_TRY promotes the protected result (exactly one value) to the revealed segment and drops the region’s segment. Node unwind (e.g. BREAK through TRY) also drops the segment.
Pushes: KOS_DYN_TRY (static extent KOS_EXT_TRY; handler targets in extent descriptor) and KosSegment.
Invariants: Extent kind KOS_EXT_TRY. Handler targets (except_pc, finally_pc, exit_pc) from extent descriptor.
Example: try/except. Extent table holds except_pc, finally_pc, exit_pc.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
PUSH_TRY |
0 |
0 |
push TRY region; extent table: except_pc, etc. |
1 |
… |
… |
… |
try body |
2 |
POP_TRY |
0 |
0 |
normal exit: pop TRY |
3 |
JUMP |
5 |
5 (-> 5) |
skip handler |
4 |
LABEL |
– |
– |
except handler (except_pc) |
5 |
LABEL |
– |
– |
exit |
KOS_OP_PUSH_FINALLY
Style: LABEL. Arg = handler/finally target.
Stack: Pushes FINALLY node and a KosSegment (like PUSH_TRY). Exception dispatch clears the segment before jumping to the finally handler. POP_FINALLY promotes exactly one value to the revealed segment and drops the region’s segment. Node unwind drops the segment when control passes through.
Pushes: KOS_DYN_FINALLY (static extent KOS_EXT_FINALLY) and KosSegment.
Invariants: Extent kind KOS_EXT_FINALLY.
Example: Push finally block. Arg = finally block pc (or extent holds it).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
PUSH_FINALLY |
3 |
3 (-> 3) |
push FINALLY; finally code at 3 |
1 |
… |
… |
… |
protected body |
2 |
POP_FINALLY |
0 |
0 |
normal exit |
3 |
LABEL |
– |
– |
finally block |
4 |
END_FINALLY |
0 |
0 |
(conceptual) |
KOS_OP_CLEAR_FINALLY
Style: NOARG.
Stack: No stack effect. Clears FINALLY region state on non-local exit; does not pop the region (POP_FINALLY does at target). Does not touch the segment (only disables the region); the segment is dropped by POP_FINALLY or unwind.
Example: Exception or unwind path before transferring to a finally handler.
KOS_OP_CLEAR_LOOP
Style: NOARG.
Stack: Clears the loop segment. Disables the top LOOP region: a BREAK or CONTINUE issued while it is disabled passes through it to the enclosing loop, and POP_LOOP takes the loop result from the region’s stack. Emitted on normal exit from a while-loop body ahead of an else clause.
Invariants: Top of chain must be KOS_DYN_LOOP. Use CLEAR_FOREACH for FOREACH extents.
Implementation:
koskari/lib/opcode/CLEAR_LOOP.c
KOS_OP_CLEAR_FOREACH
Style: NOARG.
Stack: Clears the loop segment. Disables the top FOREACH region: a BREAK or CONTINUE issued while it is disabled passes through it to the enclosing loop, and POP_FOREACH takes the loop result from the region’s stack. Emitted when a for-each iterator is exhausted naturally, ahead of an else clause.
Invariants: Top of chain must be KOS_DYN_FOREACH. Use CLEAR_LOOP for LOOP extents.
Implementation:
koskari/lib/opcode/CLEAR_FOREACH.c
KOS_OP_CLEAR_TRY
Style: NOARG.
Stack: No stack effect. Clears TRY region state on non-local exit; does not touch the segment; POP_TRY drops the segment at the target.
Invariants: Used with structured exception and non-local control flow.
KOS_OP_POP_TRY
Style: NOARG. Argument unused (or 0).
Stack: Promote one value: pop TOS from the try segment, pop the region (dropping its segment), and push the value onto the revealed segment. The segment must hold exactly one value. Clear exception state before pop.
Invariants: Top of chain must be KOS_DYN_TRY.
KOS_OP_POP_FINALLY
Style: NOARG.
Stack: Same structural behaviour as POP_TRY for the finally segment: promote one value, drop the segment, pop the region.
Invariants: Top of chain must be KOS_DYN_FINALLY.
KOS_OP_POP_LOOP
Style: NOARG.
Stack: Pop LOOP region and drop its segment; push the loop result. An enabled region delivers the result stored on the region; a region CLEAR_LOOP disabled ran its else clause, and the clause’s value, the top of the region’s stack, is the result.
Invariants: Top of chain must be KOS_DYN_LOOP (paired with PUSH_LOOP).
Implementation:
koskari/lib/opcode/POP_LOOP.c
KOS_OP_POP_FOREACH
Style: NOARG.
Stack: Pop FOREACH region and drop its segment; push the loop result. An enabled region delivers the result stored on the region, or
Nonewhen no CONTINUE set one; a region CLEAR_FOREACH disabled ran its else clause, and the clause’s value, the top of the region’s stack, is the result.Invariants: Top of chain must be KOS_DYN_FOREACH (paired with PUSH_FOREACH).
Implementation:
koskari/lib/opcode/POP_FOREACH.c
KOS_OP_POP_NS
Style: NOARG.
Stack: Pop the NS node; the revealed node’s namespace becomes active, and any values remaining on the NS node’s segment are delivered onto the revealed segment.
Example: Pool: N/A.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
POP_NS |
0 |
0 |
pop KosDynNs; restore saved namespace |
Invariants: Top of chain must be KOS_DYN_NS.
19. Object protocol
Object protocol opcodes: single Python operation on TOS (and optionally below); pop operands, push result. All Implemented unless noted.
Comparisons and predicates: OBJECT_COMPARE (CMPCOUNT) – stack
[..., a1, a2, ... aN] -> [..., result],N >= 2, selector-keyed (KosCompare packs with the count); the fused OBJECT_COMPARE_VAR / OBJECT_COMPARE_FAST carry the ternary bounds idiom with no stack inputs.Numeric: OBJECT_ADD, OBJECT_SUBTRACT, OBJECT_MULTIPLY, OBJECT_POWER, OBJECT_FLOOR_DIVIDE, OBJECT_TRUE_DIVIDE, OBJECT_MODULO, OBJECT_* (bit ops, matrix multiply).
Numeric, in-place: OBJECT_INPLACE_* (COUNT) – stack
[..., a1, a2, ... aN] -> [..., result],N >= 2, reducing left-to-right via thePyNumber_InPlace*API (POWER is strictly binary); used by the inplace-item and inplace-attr special forms.General: OBJECT_ITER, OBJECT_LEN, OBJECT_NOT, OBJECT_REPR, OBJECT_STR, OBJECT_FORMAT, OBJECT_FORMAT_CONST, OBJECT_TYPE, OBJECT_DIR, OBJECT_VARS, OBJECT_TRUTH, OBJECT_DIVMOD, OBJECT_BIT_INVERT.
Each OBJECT_* opcode in opcodes.incl has its own subsection below.
KOS_OP_OBJECT_COMPARE
Style: CMPCOUNT. Arg packs a KosCompare selector (high byte) with the reducing count (low byte).
Semantics: Chain-compare
Nstack values under the selector and push the result (N >= 2; raisesTypeErrorotherwise). The richcompare six (LT/LE/EQ/NE/GT/GE, ordinals 0-5 == Py_LT..Py_GE) chain left-to-right and push the last richcompare result. The extended selectors push a bool: IS / IS_NOT / IN / NOT_IN are strictly binary; IS_INSTANCE / IS_SUBCLASS test the first operand against each operand after it, a tuple operand opened one level, and hold on the first match.Compiler form: Emitted by the comparison, predicate, and type-check specials with a
(selector, count)pair, merged to the packed uint16 at normalize. When immediately followed byJUMP_FALSE,compressfuses the pair into CHECK_COMPARE.
KOS_OP_OBJECT_COMPARE_VAR
Style: EXTRA (CMP, CONST, VAR, CONST). Row = bare selector, low bound (pool), middle operand name, high bound (pool). Schema-static slots: no source bits, the shape is the opcode.
Stack:
[...] -> [..., result]. The ternary bounds idiom (const < x < const) with the middle operand resolved by name: chain-compare the three operands under the selector and push the chain result.Invariants: Selector is a valid KosCompare ordinal (richcompare chain semantics; extended selectors are never emitted at arity 3).
Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhen the exact CONST / VAR / CONST feeder shape meets an arity-3 comparison. In value position the OBJECT_COMPARE quartet collapses to this row alone; in branch position the arity-3 CHECK_COMPARE cannot also carry its label (five fields), so it splits into this row plusJUMP_FALSE. Lowers to OBJECT_COMPARE_FAST through the generic schema-drivenconvert_fastpath.Implementation:
koskari/lib/opcode/OBJECT_COMPARE_VAR.c(cold handler)Covered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_compare.py,tests/reproducers/test_compare_fusion.py
Example: (< 0 x 100) in value position – one dispatch.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
OBJECT_COMPARE_VAR |
0 |
(LT, c#0 (0), v#1 (‘x’), c#2 (100)) |
stack: […, bool] |
KOS_OP_OBJECT_COMPARE_FAST
Style: EXTRA (CMP, CONST, FASTVAR, CONST). Row = bare selector, low bound (pool), middle operand fast slot, high bound (pool). Schema-static slots: no source bits, the shape is the opcode.
Stack:
[...] -> [..., result]. The ternary bounds idiom (const < x < const): chain-compare the three operands under the selector and push the chain result (for JUMP_FALSE / JUMP_TRUE or value use).Invariants: Selector is a valid KosCompare ordinal (richcompare chain semantics; extended selectors are never emitted at arity 3).
Compiler form: Post-compile only: the generic
convert_fastlowering of OBJECT_COMPARE_VAR when the middle name has a fast slot.Implementation:
koskari/lib/opcode/OBJECT_COMPARE_FAST.cCovered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_compare.py,tests/reproducers/test_compare_fusion.py
Example: (< 0 x 100) in value position – one dispatch.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
OBJECT_COMPARE_FAST |
0 |
(LT, c#0 (0), fast 0 (“x”), c#1 (100)) |
stack: […, bool] |
KOS_OP_OBJECT_OPERAND
Style: OPCOUNT. Arg packs a KosOperand selector (high byte) with the reduce count (low byte).
Stack:
[..., a1, ..., aN] -> [..., result]. Reduce the N operands left-to-right under the operator (values[0]is the seed), viakos_operand_reduce(operator.c) with its two-operand PyLong fast paths.Semantics: The hottest opcode by dispatch count and by time. The handler is a prologue only: it tail-calls the body the site’s slot elected (
eval/eval_electors.c, int and float fast paths with their own guards); an empty slot or an ungated site runs the electing function once, which settles the slot.Compiler form: Emitted by the operator specials in
compile/specials/object.py; the selector is a KosOperand name.Implementation:
koskari/lib/opcode/OBJECT_OPERAND.c
KOS_OP_OBJECT_INPLACE
Style: OPCOUNT. Arg packs a KosOperand selector (high byte) with the reduce count (low byte).
Stack:
[..., a1, ..., aN] -> [..., result]. In-place reduce the N operands left-to-right (values[0]is the accumulator seed) viakos_inplace_reduce(operator.c), thePyNumber_InPlace*protocol family. The consolidated replacement for the old per-operatorOBJECT_INPLACE_*family.Semantics: The stack in-place operation behind the inplace-item and inplace-attr special forms; elected like OBJECT_OPERAND.
Implementation:
koskari/lib/opcode/OBJECT_INPLACE.c
KOS_OP_OBJECT_BIT_INVERT
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_BIT_INVERT.c
KOS_OP_OBJECT_DIR
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_DIR.c
KOS_OP_OBJECT_DIVMOD
Style: COUNT. Arg = operand count; only 2 is accepted.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_DIVMOD.c
KOS_OP_OBJECT_ITER
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_ITER.c
KOS_OP_VAR_ITER
Style: VAR. Arg = constant index of a name.
Stack:
[...] -> [..., iterator]. Fused VAR + OBJECT_ITER: resolve the name in the current frame’s namespace and push its iterator, acquired uniformly over both protocols (kos_iter_acquire).Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhen OBJECT_ITER is fed by a bare VAR load. Lowers to FAST_ITER through the simpleconvert_fastpath.Implementation:
koskari/lib/opcode/VAR_ITER.cCovered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_object_unary.py
KOS_OP_FAST_ITER
Style: FASTVAR. Arg = slot index.
Stack: As VAR_ITER, with the iterable loaded from its fast slot.
Compiler form: Post-compile only: the
convert_fastlowering of VAR_ITER when the name has a fast slot.Implementation:
koskari/lib/opcode/FAST_ITER.cCovered by:
tests/compile/test_fuse_feeders.py,tests/lib/opcode/test_object_unary.py
KOS_OP_OBJECT_LEN
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_LEN.c
KOS_OP_OBJECT_NOT
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_NOT.c
KOS_OP_OBJECT_REPR
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_REPR.c
KOS_OP_OBJECT_STR
Style: COUNT.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_STR.c
KOS_OP_OBJECT_FORMAT
Style: COUNT.
Semantics: format operation. Arg must be 1 or 2.
arg=1: pop object, call
PyObject_Format(obj, NULL).arg=2: pop rules then object, call
PyObject_Format(obj, rules). Stack effect:[..., obj] -> [..., str]or[..., obj, rules] -> [..., str].
Implementation:
koskari/lib/opcode/OBJECT_FORMAT.c
KOS_OP_OBJECT_FORMAT_CONST
Style: CONST.
Semantics: format operation with constant rules from cpool. Pop object, fetch format rules string from constant pool arg, call
PyObject_Format(obj, rules_const), push resulting string. Stack effect:[..., obj] -> [..., str].Implementation:
koskari/lib/opcode/OBJECT_FORMAT_CONST.c
KOS_OP_VAR_FORMAT
Style: VAR. Arg = constant index of a name.
Stack:
[...] -> [..., str]. Fused VAR + OBJECT_FORMAT (arg=1): resolve the name in the current frame’s namespace and pushPyObject_Format(obj, NULL).Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhen OBJECT_FORMAT (arg=1) is fed by a bare VAR load. Lowers to FAST_FORMAT through the simpleconvert_fastpath.Implementation:
koskari/lib/opcode/VAR_FORMAT.c
KOS_OP_VAR_FORMAT_CONST
Style: EXTRA (VAR, CONST). Row = obj name (pool), rules string (pool).
Stack:
[...] -> [..., str]. Fused VAR + OBJECT_FORMAT_CONST: resolve the name in the current frame’s namespace and pushPyObject_Format(obj, rules).Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhen OBJECT_FORMAT_CONST is fed by a bare VAR load. Lowers to FAST_FORMAT_CONST through the generic schema-drivenconvert_fastpath.Implementation:
koskari/lib/opcode/VAR_FORMAT_CONST.c
KOS_OP_RETURN_VAR
Style: VAR. Arg = pool index of the name.
Stack:
[...] -> [...](no stack effect). Resolves the name in the current frame’s namespace, raisingNameErrorwhen it is unbound asKOS_OP_VARwould, and returns the value exactly asKOS_OP_RETURN1 returns a popped one.Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhenKOS_OP_RETURN1 is fed by a bareKOS_OP_VAR. Lowers toKOS_OP_RETURN_FASTthrough the generic schema-drivenconvert_fastpath.Implementation:
koskari/lib/opcode/RETURN_VAR.c
KOS_OP_YIELD_VAR
Style: VAR. Arg = pool index of the name.
Stack:
[...] -> [...](no stack effect). Resolves the name in the current frame’s namespace, raisingNameErrorwhen it is unbound asKOS_OP_VARwould, and yields the value exactly asKOS_OP_YIELD1 yields a popped one. Marks the code as a generator.Compiler form: Produced by
ByteCodeProcessor.fuse_feederswhenKOS_OP_YIELD1 is fed by a bareKOS_OP_VAR. Lowers toKOS_OP_YIELD_FASTthrough the generic schema-drivenconvert_fastpath.Implementation:
koskari/lib/opcode/YIELD_VAR.c
KOS_OP_FAST_FORMAT
Style: FASTVAR. Arg = slot index.
Stack: As VAR_FORMAT, with the object loaded from its fast slot.
Compiler form: Post-compile only: the
convert_fastlowering of VAR_FORMAT when the name has a fast slot.Implementation:
koskari/lib/opcode/FAST_FORMAT.c
KOS_OP_FAST_FORMAT_CONST
Style: EXTRA (FASTVAR, CONST). Row = obj slot, rules string (pool).
Stack: As VAR_FORMAT_CONST, with the object loaded from its fast slot.
Compiler form: Post-compile only: the
convert_fastlowering of VAR_FORMAT_CONST when the name has a fast slot.Implementation:
koskari/lib/opcode/FAST_FORMAT_CONST.c
KOS_OP_RETURN_FAST
Style: FASTVAR. Arg = fast slot index.
Stack:
[...] -> [...](no stack effect). AsKOS_OP_RETURN_VAR, with the value read from the fast slot; an empty slot raisesNameErrorasKOS_OP_FASTwould.Compiler form: Post-compile only: the
convert_fastlowering of RETURN_VAR when the name has a fast slot.Implementation:
koskari/lib/opcode/RETURN_FAST.c
KOS_OP_YIELD_FAST
Style: FASTVAR. Arg = fast slot index.
Stack:
[...] -> [...](no stack effect). AsKOS_OP_YIELD_VAR, with the value read from the fast slot; an empty slot raisesNameErrorasKOS_OP_FASTwould. Marks the code as a generator.Compiler form: Post-compile only: the
convert_fastlowering of YIELD_VAR when the name has a fast slot.Implementation:
koskari/lib/opcode/YIELD_FAST.c
KOS_OP_OBJECT_TRUTH
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_TRUTH.c
KOS_OP_OBJECT_TYPE
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_TYPE.c
KOS_OP_OBJECT_VARS
Style: NOARG.
Semantics: See section 19 Object protocol overview.
Implementation:
koskari/lib/opcode/OBJECT_VARS.c
19.1 In-place variable update (VAR_INPLACE / FAST_INPLACE and _CONST forms)
Augmented assignment: fetch the current value from a name (VAR) or fast slot
(FAST), apply the in-place operator with the rhs, store the result back. No
value is pushed (the form evaluates to None). The operator is a KosOperand
selector dispatched through kos_inplace_reduce (operator.c), the same
selector set as OBJECT_OPERAND / OBJECT_INPLACE.
VAR_INPLACE – EXTRA (OPERAND, VAR). Row a0 is the bare operator
selector (one rhs popped from the stack); a1 = constant pool index of the
name. Stack: [..., rhs] -> [...].
FAST_INPLACE – EXTRA (OPERAND, FASTVAR). As above with a fast
slot. Produced by convert_fast lowering of the VAR form.
VAR_INPLACE_CONST – EXTRA (OPERAND, VAR, CONST). The compressed
single-operand form with a constant rhs: a0 is a bare KosOperand selector
(OPERAND kind), a1 the name, a2 the pooled operand. Completely
stack-free: no push, no pop. Produced by Compiler.compress fusing a
prior CONST into a VAR_INPLACE –
the (set! i (+ i 1)) / incr! loop-tail idiom. Cold handler.
FAST_INPLACE_CONST – EXTRA (OPERAND, FASTVAR, CONST). The
convert_fast lowering of the above; the hot form. A counted loop’s
back-edge increment is this single dispatch.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
6 |
FAST_INPLACE_CONST |
4 |
(ADD, fast 1 (“i”), c#1 (1), 0) |
i += 1, stack-free |
20. Delimited continuations
Delimited continuations use a block-based layout: PUSH_PROMPT establishes the reset and owns the operand segment for the delimited region; PUSH_SHIFT and POP_SHIFT delimit the shift block (handler); the continuation is the code between POP_SHIFT and POP_PROMPT.
KOS_OP_PUSH_PROMPT
Style: CONST. Arg = prompt_id (constant pool index, post-compile).
Stack: The prompt owns a fresh operand segment (so the reset body has an isolated stack), resolves the PROMPT extent at the push site and records the region’s closing pc on the node (POP_SHIFT resumes at that pc + 1), then pushes the prompt node onto the dynamic chain.
Pushes: KOS_DYN_PROMPT (static extent KOS_EXT_PROMPT; PUSH_SHIFT captures up to this prompt). PROMPT owns the segment for the delimited region; SHIFT does not create one.
Invariants: PUSH_SHIFT captures up to this prompt. An exception unwinding past a PROMPT drops the segment and unlinks the node in one step.
Compiler form: Pre-compile arg may be prompt id value or symbol; post-compile arg = pool index.
Example: reset (push prompt). Pool: 0 = prompt_id.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
PUSH_PROMPT |
0 |
0 (pid) |
push prompt (owning its segment) onto chain |
1 |
… |
… |
… |
body before shift (continuation prefix) |
2 |
PUSH_SHIFT |
0 |
0 (pid) |
capture k; enter shift block with k on stack |
3 |
… |
… |
… |
shift body (k available) |
4 |
POP_SHIFT |
0 |
0 |
return from shift without invoking |
5 |
… |
… |
… |
continuation (body after shift) |
6 |
POP_PROMPT |
0 |
0 |
drop segment; pop prompt |
KOS_OP_PUSH_SHIFT
Style: CONST. Arg = prompt_id (constant pool index, post-compile).
Stack: Captures the continuation: one walk from the top of the dynamic chain locates the nearest matching prompt while offering handle(SHIFT) to each node crossed (a generator boundary denies). The captured continuation is the delimited region with the shift expression as its hole – a cloned chain segment, so a shift hosted in a callee captures through the calling frames up to the prompt. Pushes a SHIFT marker recording the captured prompt’s instance, pushes the captured continuation on stack, and enters the shift block in place; no unwinding happens at capture. SHIFT owns the segment the shift body’s operands go on; the PROMPT’s segment keeps the region’s pending operands for the continuation to resume over.
Pushes: KOS_DYN_SHIFT (bookmark for the shift body: owns its operand segment, no handlers).
Invariants: Extent KOS_EXT_SHIFT pairs with POP_SHIFT. Stack block is owned by PROMPT, not SHIFT.
Errors: A walk that exhausts the chain without meeting a matching prompt raises
KoskariPromptNotFound; a node that denies handle(SHIFT) (a generator boundary) raisesKoskariPromptUnreachablewith the denying boundary recorded. Both carryprompt_idandoperation.Compiler form: Pre-compile arg may be prompt id value/symbol; post-compile arg = pool index.
Example: shift k: body. Capture k, run shift body with k on stack. Pool: 0 = prompt_id.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
2 |
PUSH_SHIFT |
0 |
0 (pid) |
capture k in place; push SHIFT marker; enter shift block with k on stack |
KOS_OP_POP_SHIFT
Style: NOARG.
Stack: Pops TOS as result and resolves the delimiter by the prompt instance the SHIFT recorded at capture. For a live reset: builds a transfer plan that unwinds through the SHIFT and PROMPT (dropping both and the PROMPT’s segment), injects the result onto the outer frame’s stack, and resumes at the closing pc the prompt recorded at push, + 1. For an invocation prompt (created by invoking a captured k; no POP_PROMPT pairs with it): the result is the value of that k-invocation, delivered at the invoke site through the paired DELIM bookmark.
Invariants: Must be inside a PUSH_SHIFT extent (parent is PROMPT extent). The segment owned by the PROMPT is dropped as part of the TRUNCATE_AND_INJECT step; the injected value lands on the frame’s stack below the former block boundary.
Compiler form: No argument.
Example: Shift handler returns value without invoking k.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
4 |
POP_SHIFT |
0 |
0 |
pop result; unwind through SHIFT+PROMPT; drop segment; inject result onto outer stack |
KOS_OP_POP_PROMPT
Style: NOARG.
Stack: Normal case (no active continuation return): pops TOS as the reset result, drops the PROMPT’s segment, unlinks the prompt from the chain, and pushes the result onto the parent stack. Invoked-continuation return case: the walk down from the current node finds a
KOS_DYN_DELIMbookmark (modePOP_PROMPTfor a grafted re-invoke,INPLACEfor an in-place first invoke), passing invocation prompts and stopping at a live prompt; it pops TOS as result, unwinds to the delim, delivers the result at the invoke site per the delim’s return metadata (an INPLACE delim restores the displaced frame state and re-links the suspended handler first), and resumes there.Invariants: Top of chain must be the matching prompt when POP_PROMPT executes. When returning from an invoked delimited continuation (return path recorded on
KOS_DYN_DELIM), POP_PROMPT transfers control back to the call site with the result value instead of exiting normally. Exactly one value is consumed from the PROMPT’s segment and one is injected to the outer stack.Push-return model: Delimited invoke uses PUSH (graft frames onto current chain). When the continuation runs and hits POP_PROMPT, it consults the
KOS_DYN_DELIMmarker installed for that invoke and resumes at the call site with the value on stack.Exception propagation: If an exception escapes past the PROMPT during unwinding, the unwind drops the segment and unlinks the PROMPT, then continues. No POP_PROMPT opcode executes in this path.
Example: End of reset body.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
6 |
POP_PROMPT |
0 |
0 |
pop result; drop segment; pop prompt; push result to outer stack |
21. Undelimited continuations (call/cc)
CAPTURE_CC captures the continuation of the CC dynamic extent (from the current pc until the extent is exited). Invoking that continuation is a non-local jump to the POP_CC opcode, with a value pushed onto the stack; POP_CC then runs (pops the CC block) and execution continues at the next instruction (the PUSH_CC resume target).
KOS_OP_PUSH_CC
Style: NOARG. The instruction has no argument. The resume PC (instruction index to continue at when the continuation is invoked) is not stored in the bytecode; the evaluator obtains it from the block table (extent table): the CC extent for this PUSH_CC has
pop_pcat the matching POP_CC, and the resume PC ispop_pc + 1(the instruction immediately after POP_CC).Stack: Pushes CC block onto dynamic chain. Normal exit: body runs, then POP_CC runs, then execution continues at the next instruction (resume). On invoke: jump to POP_CC with value on stack; POP_CC runs; continue at next instruction (same resume PC from block table).
Pushes: KOS_DYN_CC (static extent KOS_EXT_CC).
Example: (call/cc (lambda (k) (k 42))) -> 42. Body captures k, pushes 42, CALL 1 invokes k(42); that jumps to POP_CC (index 4) with stack […, 42]; POP_CC runs; execution continues at 5 (resume), RETURN 1 yields 42.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
PUSH_CC |
0 |
0 |
push CC block; resume at 5 (= pop_pc+1 from block table) |
1 |
CAPTURE_CC |
0 |
0 |
stack before: […]; after: […, continuation] |
2 |
CONST |
0 |
0 (42) |
stack: […, continuation, 42] |
3 |
CALL |
1 |
1 |
invoke continuation with one arg -> jump to POP_CC (4) with […, 42] |
4 |
POP_CC |
0 |
0 |
invoke lands here with value on stack; pop CC; next pc = 5 (resume) |
5 |
RETURN |
1 |
1 |
yield TOS (42) |
KOS_OP_POP_CC
Style: NOARG.
Stack: Pops CC block from dynamic chain. When the captured continuation is invoked, the VM jumps to this opcode with the invoked value (or values) on the stack; this opcode then runs (pops the CC block) and execution continues at the next instruction (the PUSH_CC resume target).
Example: In the PUSH_CC table above, POP_CC at index 4 is the jump target when the continuation is invoked; stack holds the value(s) passed to the continuation; after POP_CC, execution continues at index 5 (resume).
KOS_OP_CAPTURE_CC
Style: COUNT, 0 or 1.
Stack: Captures the continuation of the CC dynamic extent (from current pc until the extent is exited at POP_CC); pushes it (KosPyContinuation) onto stack. With arg 0 (
let/cc) the stack effect is[...] -> [..., continuation]. With arg 1 (call/cc) the callee on TOS is set aside for the capture and put back beneath the continuation,[..., fn] -> [..., fn, continuation], so the captured stack holds the form’s enclosing operands and not the callee; the CALL 1 that follows applies fn to the continuation. Invoking the continuation is a non-local jump to the POP_CC opcode with a value pushed onto the stack.Example: See the PUSH_CC disassembly table: at index 1, CAPTURE_CC pushes the continuation. Invoking it (e.g. CALL 1 with 42) jumps to POP_CC (index 4) with stack […, 42]; POP_CC runs; execution continues at index 5 (resume).
22. Dynamic wind
Unified extent wind/unwind uses kos_extent_run_wind and kos_extent_run_unwind,
which dispatch by dynamic-chain node kind. See compile/capture-cc
and compile/dyn-wind.
KOS_OP_PUSH_WIND
Style: COUNT. Arg = 1 (before only) or 2 (both before and after).
Stack: For arg=2:
[..., before, after](before below, after above). Pops thunks; each must be callable or nil. For arg=1:[..., before]. Pushes KOS_DYN_WIND extent; runs before thunk on entry (via normal call path; may return KOS_DYN_UNWIND_ASYNC_STARTED).Pushes: KOS_DYN_WIND (static extent KOS_EXT_WIND).
Example: See extent-wind-unwind.md; thunks are invoked via kos_callable_call.
KOS_OP_POP_WIND
Style: NOARG.
Stack: Pops TOS (the body result) into the wind node, pops wind from the dynamic chain, and runs the after thunk (if entered and non-null) via kos_dyn_wind_unwind; the body result is delivered to the revealed segment when the thunk completes (or immediately when there is none). May return KOS_DYN_UNWIND_ASYNC_STARTED when the thunk pushes a frame.
Invariants: Dyn top must be KOS_DYN_WIND; otherwise RuntimeError.
23. Parameterize extent and parameter reads
KOS_OP_PUSH_PARAM
Style: CONST. Arg = constant pool index of names tuple
(name_0, name_1, ...).Stack:
[..., val_0, val_1, ..., val_{n-1}]->[]. Values consumed; names come from constant.Pushes: KOS_DYN_PARAM (extent kind KOS_EXT_PARAM; owns its operand segment). Builds dict from names and values, enters param extent.
Invariants: Constant at arg must be a tuple of names; stack must have at least
len(names)values.Example:
(parameterize ((x 1) (y 2)) body)compiles to push values 1, 2, then PUSH_PARAM with names("x", "y").
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
1 |
1 (1) |
push 1 |
1 |
CONST |
2 |
2 (2) |
push 2 |
2 |
PUSH_PARAM |
0 |
0 (names) |
pop 2 values, push param |
3 |
… |
… |
… |
body |
N |
POP_PARAM |
0 |
0 |
pop param extent |
KOS_OP_POP_PARAM
Style: NOARG.
Stack: No change.
Pops: KOS_DYN_PARAM from dynamic chain. Restores the cells the extent displaced in the context’s shadow table. The PARAM node owns its operand segment; any values remaining on it are delivered onto the revealed segment, so the observable stack effect is unchanged.
Invariants: Dyn top must be KOS_DYN_PARAM; otherwise RuntimeError.
Example: See PUSH_PARAM table.
KOS_OP_PARAM
Style: EXTRA. Schema CONST (parameter name), COUNT (0 or 1 stacked defaults).
Stack:
[]->[value]at count 0;[default]->[value]at count 1.Resolves: the enclosing parameterize extent (the context’s shadow table), then the root scope of the context’s domain. Writes to neither, and creates no entry on a miss.
Invariants: On a miss at count 0, raises NameError. At count 1 the stacked default answers a miss, and is dropped on a hit.
Example:
(parameterq x)compiles to PARAM("x", 0);(parameterq x (compute))compiles the expression, then PARAM("x", 1).
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
CONST |
0 |
“fallback” |
push the default |
1 |
PARAM |
0 |
(“x”, 1) |
resolve x, else keep default |
KOS_OP_PARAM_CONST
Style: EXTRA. Schema CONST (parameter name), CONST (default value).
Stack:
[]->[value].Resolves: as PARAM, with the default coming from the constant pool rather than the stack. Never raises for an unbound name.
Invariants: Both constants must be present in the pool.
Example:
(parameterq x 42)compiles to PARAM_CONST("x", 42).
24. Sentinel
KOS_OP_THEEND
Style: NOARG.
Stack: Unreachable for normal execution.
Invariants: If execution reaches THEEND, the VM raises RuntimeError. THEEND must always be last in opcodes.incl.
Example: Sentinel at end of code; no legitimate execution path reaches it.
index |
opcode |
arg |
arg view |
comment |
|---|---|---|---|---|
0 |
RETURN |
1 |
1 |
normal exit |
1 |
THEEND |
0 |
0 |
unreachable; VM raises if pc lands here |