Skip to main content
T TON Adoption
← Glossary
NODE/03 · Term

Continuation

The primary computational primitive of TVM: a 'continuation' — pointer to a code segment plus execution context. Replaces conventional procedures and functions — every TVM control-flow primitive is built on continuations.

Aliases: tvm continuation

Continuation is the fundamental computational primitive of TVM, replacing the conventional notions of “function”, “procedure”, and “return address”. It’s a structure holding a pointer to a code segment plus execution context (stack, registers).

Why it matters

TVM has no CALL instruction in the Z80/x86 sense — only continuation manipulations. IFJMPREF { ... }, CALLREF, RETALT, and others all operate at the continuation level. This gives you:

  • Higher-order functions in FunC/Tact/Tolk for free: a continuation is a first-class value.
  • Try/catch through the c2 alternative continuation.
  • Loops via recursion or WHILE { c1 } { c2 } combinators.

Why it’s strange coming from EVM

For developers arriving from EVM, this is the most unusual TVM concept. It’s worth reading TVM Whitepaper §4 (“Control flow, continuations, exceptions”) before writing your first non-trivial contract. Without understanding continuations you can’t really read a bridge or DEX’s TASM.

Registers c0-c5: where continuations live

TVM keeps continuations in dedicated control registers:

RegisterPurpose
c0Return continuation — where RET/RETALT jump after completion
c1Alternative continuation — used by RETALT, handles exceptions
c2Exception handler — THROW jumps here
c3Dictionary of procedure IDs — acts as the contract’s “function table”
c4Persistent storage cell — written back to state on commit
c5Actions output — list of outgoing messages

When a get-method or receive function starts, the runtime pre-populates c0 so that RET correctly terminates execution and returns the result tuple.

Example: try/catch via c2

In FunC, error handling looks like two continuations — the normal path and a handler:

try {
  throw_unless(error_code::not_owner, equal_slices(sender, owner));
  do_owner_only_thing();
} catch (_, exno) {
  send_text_message(sender, "Access denied");
}

The compiler unrolls this into TVM instructions: PUSHCONT { ... } PUSHCONT { ... } TRY — two continuations land on the stack, TRY installs the second one as c2 and executes the first.

Example: get-method ABI built on continuations

c3 is a dictionary keyed by method-ID (CRC16 of the name), with method bodies as continuations. When tonapi calls runGetMethod, TVM does:

PUSHINT <method_id>
PUSH c3
DICTPUSHCONT  ; look up in the dictionary, push the continuation
EXECUTE       ; call it

To add a custom method to your contract you register an entry in the c3 dictionary at compile time (global_method_id(...) in FunC, get fun in Tact).

Comparison with EVM/Move

ConceptEVMMoveTVM
Function callCALL opcode, stack frameCall bytecode, framePUSHCONT + CALLREF — continuation as value
ReturnRETURNRetRET → c0
ExceptionsREVERTabortTHROW → c2
Higher-orderNot supported until Cancun (function-pointer hacks)Generics + closuresBuilt-in: continuation == first-class

An EVM developer is used to “a method at an address in bytecode” — on TVM the relevant chunk of code is passed in as a parameter.

Where to inspect continuations when debugging

  • TON Sandbox (@ton/sandbox) — step-by-step execution shows c0/c1/c2 after every instruction.
  • tonscan execution trace — surfaces the final c4 value (storage delta) and c5 (out_msgs).
  • func-js compiler —debug-info — annotates which PUSHCONT corresponds to which source function.
  • TVM — overall virtual-machine architecture.
  • Get-method — practical use of the c3 dictionary.
  • Opcode — list of instructions that manipulate continuations.

Related terms