Akron VM y Bytecode
Máquina virtual de propósito general basada en registros: opcodes, codificación de valores y formato binario.
Akron es la VM de bytecode de propósito general de Achronyme — un intérprete basado en registros que ejecuta archivos .achb producidos por el compilador de bytecode. Corre el lenguaje Achronyme en tiempo de ejecución (ach run) y evalúa bloques prove {} en modo VM.
Akron está emparejado con Artik, la VM dedicada a cómputo de testigos. La división es intencional: Akron maneja scripting y estado de heap mutable con GC, mientras que Artik maneja la matemática de testigos sin efectos secundarios, sin heap ni GC.
Arquitectura
Fuente (.ach)
|
v
Compilador de Bytecode -> Prototipos de funcion + bytecode
|
v
Serializador -> archivo binario .achb
|
v
Cargador -> heap + pila + frames de Akron
|
v
Interprete -> Ejecucion basada en registros
Estructura de la VM
Akron {
heap: Heap, // arenas tipadas + GC
stack: [Value; 65536], // pila de registros fija
frames: Vec<CallFrame>, // pila de llamadas
globals: Vec<GlobalEntry>, // variables globales
natives: Vec<NativeObj>, // funciones integradas
open_upvalues: lista enlazada, // variables de pila capturadas
stress_mode: bool, // forzar GC en cada ciclo
}
Frames de Llamada
Cada llamada a función apila un CallFrame:
CallFrame {
closure: u32, // handle a Closure en el heap
ip: usize, // puntero de instruccion
base: usize, // offset base en la pila
dest_reg: usize, // donde almacenar el valor de retorno
}
El registro R[i] en el frame actual mapea a stack[frame.base + i].
Representación de Valores
Los valores son enteros de 64 bits etiquetados — sin boxing para tipos comunes:
Bits 63..60 = etiqueta de 4 bits
Bits 59..0 = payload de 60 bits
Etiquetas
| Etiqueta | Nombre | Payload |
|---|---|---|
| 0 | INT | entero con signo i60 (en linea) |
| 1 | NIL | - |
| 2 | FALSE | - |
| 3 | TRUE | - |
| 4 | STRING | handle u32 -> arena de strings |
| 5 | LIST | handle u32 -> arena de listas |
| 6 | MAP | handle u32 -> arena de mapas |
| 7 | FUNCTION | handle u32 -> arena de funciones |
| 8 | FIELD | handle u32 -> arena de campos |
| 9 | PROOF | handle u32 -> arena de pruebas |
| 10 | NATIVE | handle u32 -> tabla de nativos |
| 11 | CLOSURE | handle u32 -> arena de closures |
| 12 | ITER | handle u32 -> arena de iteradores |
| 14 | BYTES | handle u32 -> arena de bytes (constantes ProveIR) |
| 15 | CIRCOM_HANDLE | handle u32 -> plantillas Circom |
Los enteros (etiqueta 0) son el tipo mas comun — usar la etiqueta 0 significa que no se necesita enmascaramiento para el caso comun.
Rango de enteros: -2^59 a 2^59 - 1 (576,460,752,303,423,487). El desbordamiento genera IntegerOverflow.
Codificación de Instrucciones
Cada instrucción es un u32 en uno de dos formatos:
Formato ABC
[opcode:8][A:8][B:8][C:8]
Usado para instrucciones de 3 operandos como Add R[A] = R[B] + R[C].
Formato ABx
[opcode:8][A:8][Bx:16]
Usado para instrucciones con un operando de 16 bits, como LoadConst R[A] = K[Bx] o Jump IP = Bx.
Opcodes
Constantes y Movimientos
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
LoadConst | 0 | ABx | R[A] = K[Bx] — cargar del pool de constantes |
LoadTrue | 1 | A | R[A] = true |
LoadFalse | 2 | A | R[A] = false |
LoadNil | 3 | A | R[A] = nil |
Move | 5 | AB | R[A] = R[B] |
Aritmética
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
Add | 10 | ABC | R[A] = R[B] + R[C] |
Sub | 11 | ABC | R[A] = R[B] - R[C] |
Mul | 12 | ABC | R[A] = R[B] * R[C] |
Div | 13 | ABC | R[A] = R[B] / R[C] |
Mod | 14 | ABC | R[A] = R[B] % R[C] |
Pow | 15 | ABC | R[A] = R[B] ^ R[C] |
Neg | 16 | AB | R[A] = -R[B] |
Comparación y Lógica
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
Eq | 20 | ABC | R[A] = R[B] == R[C] |
Lt | 21 | ABC | R[A] = R[B] < R[C] |
Gt | 22 | ABC | R[A] = R[B] > R[C] |
NotEq | 23 | ABC | R[A] = R[B] != R[C] |
Le | 24 | ABC | R[A] = R[B] <= R[C] |
Ge | 25 | ABC | R[A] = R[B] >= R[C] |
LogNot | 26 | AB | R[A] = !R[B] |
Closures y Upvalues
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
GetUpvalue | 34 | AB | R[A] = Upvalue[B] |
SetUpvalue | 35 | AB | Upvalue[B] = R[A] |
CloseUpvalue | 36 | A | Cerrar upvalue en slot de pila A |
Funciones
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
Return | 54 | A | Retornar R[A] del frame actual |
Call | 55 | ABC | R[A] = Call(R[B], R[B+1]..R[B+C-1]) |
Closure | 56 | ABx | R[A] = Closure(K[Bx]) |
Flujo de Control
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
Jump | 60 | Bx | IP = Bx |
JumpIfFalse | 61 | ABx | Si !R[A] entonces IP = Bx |
GetIter | 65 | AB | R[A] = Iterator(R[B]) |
ForIter | 66 | ABx | Siguiente elemento o saltar a Bx |
Globales
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
DefGlobalVar | 98 | ABx | Definir global mutable |
DefGlobalLet | 99 | ABx | Definir global inmutable |
GetGlobal | 100 | ABx | R[A] = Global[K[Bx]] |
SetGlobal | 101 | ABx | Global[K[Bx]] = R[A] |
Print | 102 | A | Imprimir R[A] |
Estructuras de Datos
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
BuildList | 150 | ABC | R[A] = [R[B]..R[B+C-1]] |
BuildMap | 151 | ABC | R[A] = {R[B]:R[B+1], ...} |
GetIndex | 152 | ABC | R[A] = R[B][R[C]] |
SetIndex | 153 | ABC | R[A][R[B]] = R[C] |
ZK y Despacho
| Opcode | Codigo | Formato | Descripcion |
|---|---|---|---|
Prove | 160 | - | Compilar + verificar circuito ZK |
MethodCall | 161 | ABC | Despacho de metodo R[A] = R[B].metodo(args) |
CallCircomTemplate | 162 | ABC | Invocar un handle de plantilla Circom registrado |
Especiales
| Opcode | Codigo | Descripcion |
|---|---|---|
Nop | 255 | Sin operacion |
Objetos de Función
Cada función compilada produce un struct Function en el heap:
Function {
name: String, // para depuracion
arity: u8, // conteo de parametros
max_slots: u16, // uso pico de registros
chunk: Vec<u32>, // instrucciones de bytecode
constants: Vec<Value>, // pool de constantes
upvalue_info: Vec<u8>, // pares [is_local, index]
line_info: Vec<u32>, // numero de linea por instruccion
}
El vector line_info es paralelo a chunk — cada instrucción tiene un número de línea fuente para reporte de errores.
Formato Binario (.achb)
El formato de archivo .achb (versión 9):
Magic: b"ACH\x09" (4 bytes)
Metadata: max_slots (u16 LE)
Global Strings:
count (u32 LE)
por cada uno: length (u32 LE) + bytes UTF-8
Global Constants:
count (u32 LE)
por cada uno: tag (u8) + payload
INT (0): i64 LE
STRING (1): handle u32 LE
FIELD (8): 4 x u64 LE (limbs Montgomery)
BYTES (14): u32 LE length + bytes (blobs ProveIR)
NIL (255): (sin payload)
Prototypes:
count (u32 LE)
por cada uno:
name_len (u32 LE) + bytes del nombre
arity (u8)
max_slots (u16 LE)
const_count (u32 LE) + constantes
upvalue_count (u32 LE) + info de upvalue
bytecode_len (u32 LE) + instrucciones (u32 LE cada una)
Main Bytecode:
instruction_count (u32 LE)
instrucciones (u32 LE cada una)
El formato es compatible con el módulo loader de Akron, que deserializa en objetos del heap.
Disposición de Variables Globales
Indice: 0..22 23..
Nativos Globales de usuario
Los primeros 23 slots (0-22) están reservados para funciones nativas. Las globales definidas por el usuario comienzan en el índice 23 (USER_GLOBAL_START).
Relación con Artik
Akron y Artik son VMs hermanas con roles disjuntos:
| Akron | Artik |
|---|---|
Scripting de proposito general + prove {} | Computo de testigos para circuitos |
| Valores etiquetados, 13+ tipos | Solo field elements + enteros de ancho fijo |
| GC mark-sweep, arenas tipadas | Sin heap, sin GC |
| ~40 opcodes, formato de 3 operandos | ~25 opcodes, registros tipados |
Invocado por ach run, modo VM | Despachado desde R1CS witness-gen (WitnessOp::ArtikCall) |
Ver VM de Testigos Artik para los detalles del camino de testigos.
Archivos Fuente
| Componente | Archivo |
|---|---|
| Opcodes | akron/src/opcode.rs |
| Interprete VM | akron/src/machine/vm.rs |
| Frames de llamada | akron/src/machine/frame.rs |
| Bucle del interprete | akron/src/machine/interpreter.rs |
| Despacho de nativos | akron/src/specs.rs |
| Metodos de prototipo | akron/src/machine/methods/ |
| Codificacion de valores | memory/src/value.rs |
| Struct Function | memory/src/heap.rs |
| Compilador de bytecode | akronc/src/codegen.rs |
| Compilador de funciones | akronc/src/function_compiler.rs |
| Serializador binario | cli/src/commands/compile.rs |
| Cargador binario | akron/src/loader.rs |