Procedures#

class unit.Procedure(name, *, context=None, inlining=None, optimize_translation=True)#

A procedure represents a single function to be compiled. Provides methods to emit stack-based IR instructions.

Parameters:
Example#
# Simple usage
proc = unit.Procedure("main")
proc.load_integer(42)
proc.return_value()

# With explicit options
proc = unit.Procedure(
    "helper",
    context=ctx,
    inlining="never",
    optimize_translation=False,
)

Properties

property inlining: str | None#

Get or set the inlining behavior. "force", "never", or None.

property optimize_translation: bool#

Get or set whether register IR optimization runs during compilation.

Compilation

optimize() None#

Run stack IR optimization passes: inlining, constant folding, dead store elimination, and local variable optimization. Call this before compile().

Raises:

unit.Error – If optimization fails.

compile(platform=None) CompiledProcedure#

Compile the procedure to machine code.

Parameters:

platform (Platform) – Target platform. Defaults to Platform.host().

Returns:

A compiled procedure ready for JIT or object file output.

Return type:

CompiledProcedure

Raises:

unit.Error – If compilation fails.

instructions_text(*, visualize_stack_effect=True, ignore_errors=True) str#

Return the stack IR as a string. Useful for debugging.

Parameters:
  • visualize_stack_effect (bool) – Show stack state after each instruction.

  • ignore_errors (bool) – Suppress errors from incomplete procedures.

Stack Operations

load_integer(value) None#

Push an integer constant onto the stack. See UNIT_OP_LOAD_INTEGER.

Stack effect: -- value

Parameters:

value (int) – The integer to push.

Raises:

TypeError – If value is not an int.

load_string(value) None#

Push a string constant onto the stack. See UNIT_Procedure_AddStringLoad().

Stack effect: -- pointer

Parameters:

value (str) – The string to push. Copied internally.

Raises:

TypeError – If value is not a str.

load_argument(arg_number) None#

Push a function argument onto the stack. Argument 0 is the first parameter. See UNIT_OP_LOAD_ARGUMENT.

Stack effect: -- value

Parameters:

arg_number (int) – The argument index.

load_local(id) None#

Push a local variable onto the stack. See UNIT_OP_LOAD_LOCAL.

Stack effect: -- value

Parameters:

id (int) – The local variable index.

store_local(id) None#

Pop the top of the stack into a local variable. See UNIT_OP_STORE_LOCAL.

Stack effect: value --

Parameters:

id (int) – The local variable index.

pop() None#

Discard the top of the stack. See UNIT_OP_POP.

Stack effect: value --

copy(offset_from_top) None#

Duplicate the stack item at the given depth. copy(0) duplicates the top. See UNIT_OP_COPY.

Stack effect: -- value

Parameters:

offset_from_top (int) – Depth of the item to copy (0 = top).

proc.load_integer(10)   # stack: [10]
proc.load_integer(20)   # stack: [10, 20]
proc.copy(1)            # stack: [10, 20, 10]
swap(offset_from_top) None#

Swap the top of the stack with the item at the given depth. See UNIT_OP_SWAP.

Stack effect: unchanged (items rearranged)

Parameters:

offset_from_top (int) – Depth of the item to swap with (1 = second item).

Arithmetic

add() None#

Pop two values, push their sum. See UNIT_OP_ADD.

Stack effect: a b -- a+b

subtract() None#

Pop two values, push their difference. See UNIT_OP_SUBTRACT.

Stack effect: a b -- a-b

multiply() None#

Pop two values, push their product. See UNIT_OP_MULTIPLY.

Stack effect: a b -- a*b

divide() None#

Pop two values, push their quotient (integer division). See UNIT_OP_DIVIDE.

Stack effect: a b -- a/b

modulo() None#

Pop two values, push the remainder. See UNIT_OP_MODULO.

Stack effect: a b -- a%b

Comparisons

All comparisons pop two values and push a comparison result consumed by jump_if_true() or jump_if_false().

compare_equal() None#

See UNIT_OP_COMPARE_EQUAL.

Stack effect: a b -- result

compare_not_equal() None#

See UNIT_OP_COMPARE_NOT_EQUAL.

Stack effect: a b -- result

compare_less() None#

See UNIT_OP_COMPARE_LESS.

Stack effect: a b -- result

compare_less_equal() None#

See UNIT_OP_COMPARE_LESS_EQUAL.

Stack effect: a b -- result

compare_greater() None#

See UNIT_OP_COMPARE_GREATER.

Stack effect: a b -- result

compare_greater_equal() None#

See UNIT_OP_COMPARE_GREATER_EQUAL.

Stack effect: a b -- result

Control Flow

create_jump_label(name) JumpLabel#

Create a jump target. Place it later with use_label().

Parameters:

name (str) – A descriptive name for the label.

Returns:

A label handle.

Return type:

JumpLabel

Raises:

TypeError – If name is not a str.

use_label(label) None#

Place a label at the current position. All jumps to this label target the next instruction emitted.

Parameters:

label (JumpLabel) – The label to place.

jump(label) None#

Unconditional jump. See UNIT_OP_JUMP_TO.

Parameters:

label (JumpLabel) – The target label.

jump_if_true(label) None#

Pop a comparison result. Jump if true. See UNIT_OP_JUMP_IF_TRUE.

Stack effect: comparison --

Parameters:

label (JumpLabel) – The target label.

jump_if_false(label) None#

Pop a comparison result. Jump if false. See UNIT_OP_JUMP_IF_FALSE.

Stack effect: comparison --

Parameters:

label (JumpLabel) – The target label.

end = proc.create_jump_label("end")
proc.load_integer(5)
proc.load_integer(5)
proc.compare_equal()
proc.jump_if_true(end)
# ... not-equal path ...
proc.use_label(end)
# ... equal path continues here ...

Calls

call_name(name, num_args) None#

Call an external function by name. The top num_args stack items are passed as arguments (first argument pushed first). The return value is pushed onto the stack. See UNIT_Procedure_AddCallName().

Stack effect: arg1 arg2 ... argN -- result

Parameters:
  • name (str) – The function name (resolved via dlsym or SymbolMap during JIT).

  • num_args (int) – Number of arguments.

Raises:
  • TypeError – If name is not a str or num_args is not an int.

  • ValueError – If num_args is negative.

proc.load_string("%d\n")
proc.load_integer(42)
proc.call_name("printf", 2)
proc.pop()  # discard printf return value
return_value() None#

Pop the top of the stack and return it to the caller. See UNIT_OP_RETURN_VALUE.

Stack effect: value --

exit() None#

Terminate the process immediately. See UNIT_OP_EXIT.

Memory Access

read_bytes(num_bytes) None#

Pop an address, read num_bytes from it (1, 2, 4, or 8), push the value. See UNIT_OP_READ_BYTES.

Stack effect: address -- value

Parameters:

num_bytes (int) – Number of bytes to read.

write_bytes(num_bytes) None#

Pop an address and a value, write num_bytes of the value to the address. See UNIT_OP_WRITE_BYTES.

Stack effect: address value --

Parameters:

num_bytes (int) – Number of bytes to write.

address_of(id) None#

Push the memory address of a local variable. See UNIT_OP_ADDRESS_OF.

Stack effect: -- address

Parameters:

id (int) – The local variable index.

Jump labels#

class unit.JumpLabel#

A handle to a jump target, returned by Procedure.create_jump_label(). Not constructed directly.

Platforms#

class unit.Platform(architecture, abi)#

Target platform for compilation.

Parameters:
  • architecture (str) – "amd64" or "aarch64".

  • abi (str) – "systemv", "apple", or "win64".

Example#
# Explicit platform
platform = unit.Platform("amd64", "systemv")
compiled = proc.compile(platform)

# Host platform (auto-detected)
compiled = proc.compile()  # uses Platform.host() internally
classmethod host() Platform#

Return the platform of the current machine.

architecture: str#

"amd64" or "aarch64".

abi: str#

"systemv", "apple", or "win64".

Compiled procedures#

class unit.CompiledProcedure#

A compiled procedure, ready for JIT execution or object file output. Returned by Procedure.compile(). Not constructed directly.

jit(extra_symbols=None) ExecutableBuffer#

JIT compile and return an executable buffer. Symbols are resolved via dlsym. Custom symbols can be provided for JIT-to-JIT calls or trampolines.

Parameters:

extra_symbols (dict) – Optional mapping of symbol names to integer addresses. See Symbol resolution.

Returns:

A callable executable buffer.

Return type:

ExecutableBuffer

Raises:

unit.Error – If JIT compilation fails.

Example#
# Simple JIT
buf = compiled.jit()
result = buf(42)

# With custom symbols
import ctypes
addr = ctypes.cast(my_func, ctypes.c_void_p).value
buf = compiled.jit(extra_symbols={"my_func": addr})
write_object_file(path, format) None#

Write the compiled procedure to an object file.

Parameters:
  • path (str) – Output file path.

  • format (str) – "elf", "macho", or "pe".

Raises:
  • ValueError – If format is not recognized.

  • unit.Error – If writing fails.

Example#
compiled.write_object_file("output.o", "elf")
translation_text() str#

Return the register IR as a string. Useful for debugging.

Executable buffers#

class unit.ExecutableBuffer#

A JIT-compiled function, callable directly. Returned by CompiledProcedure.jit(). Not constructed directly.

Arguments are automatically converted to ctypes types:

  • intc_int64

  • floatc_double

  • strc_char_p (encoded to UTF-8)

  • bytesc_char_p

The return type is always c_int64. For finer control, use the address property with ctypes directly.

__call__(*args) int#

Call the JIT-compiled function.

Raises:

TypeError – If an argument has an unsupported type.

buf = compiled.jit()
result = buf(10, 20)  # call with two int arguments
address: int#

The raw function pointer address. Use with ctypes for custom calling conventions or return types.

import ctypes
func_type = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double)
fn = func_type(buf.address)
result = fn(3.14)

Symbol resolution#

The extra_symbols parameter on CompiledProcedure.jit() accepts a dictionary mapping symbol names to integer addresses. This is used for custom symbol resolution during JIT compilation – for example, to provide trampolines for calling between JIT-compiled functions.

Example#
import ctypes

@ctypes.CFUNCTYPE(ctypes.c_int64, ctypes.c_int64)
def my_trampoline(n):
    return n * 2

addr = ctypes.cast(my_trampoline, ctypes.c_void_p).value
buf = compiled.jit(extra_symbols={"my_func": addr})

Symbols in the dictionary are checked before falling back to dlsym. See UNIT_SymbolMap for the underlying C API.