VM y Bytecode
La VM de Achronyme es un intérprete de bytecode basado en registros. Ejecuta archivos .achb compilados usando una pila de tamaño fijo de 65,536 slots de Value.
Arquitectura
Sección titulada «Arquitectura»Fuente (.ach) │ ▼Compilador de Bytecode → Prototipos de función + bytecode │ ▼Serializador → archivo binario .achb │ ▼Cargador → heap + pila + frames de la VM │ ▼Intérprete → Ejecución basada en registrosEstructura de la VM
Sección titulada «Estructura de la VM»VM { heap: Heap, // arenas tipadas + GC stack: [Value; 65536], // pila de registros de tamaño fijo frames: Vec<CallFrame>, // pila de llamadas globals: Vec<GlobalEntry>, // variables globales natives: Vec<NativeObj>, // 23 funciones integradas open_upvalues: lista enlazada, // variables de pila capturadas stress_mode: bool, // forzar GC en cada ciclo}Frames de Llamada
Sección titulada «Frames de Llamada»Cada llamada a función apila un CallFrame:
CallFrame { closure: u32, // handle a Closure en el heap ip: usize, // puntero de instrucción base: usize, // offset base en la pila dest_reg: usize, // dónde almacenar valor de retorno}El registro R[i] en el frame actual mapea a stack[frame.base + i].
Representación de Valores
Sección titulada «Representación de Valores»Los valores son enteros de 64 bits etiquetados — sin boxing para tipos comunes:
Bits 63..60 = etiqueta de 4 bitsBits 59..0 = payload de 60 bitsEtiquetas
Sección titulada «Etiquetas»| Etiqueta | Nombre | Payload |
|---|---|---|
| 0 | INT | entero con signo i60 (en línea) |
| 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 (BN254) |
| 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 |
Los enteros (etiqueta 0) son el tipo de valor más común — usar la etiqueta 0 significa que no se necesita enmascaramiento para el caso común.
Rango de enteros: -2^59 a 2^59 - 1 (576,460,752,303,423,487). El desbordamiento genera IntegerOverflow.
Codificación de Instrucciones
Sección titulada «Codificación de Instrucciones»Cada instrucción es un u32 en uno de dos formatos:
Formato ABC
Sección titulada «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
Sección titulada «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
Sección titulada «Opcodes»Constantes y Movimientos
Sección titulada «Constantes y Movimientos»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Aritmética»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Comparación y Lógica»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Closures y Upvalues»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Funciones»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Flujo de Control»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Globales»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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
Sección titulada «Estructuras de Datos»| Opcode | Código | Formato | Descripción |
|---|---|---|---|
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] |
| Opcode | Código | Formato | Descripción |
|---|---|---|---|
Prove | 160 | — | Compilar + verificar circuito ZK |
Especiales
Sección titulada «Especiales»| Opcode | Código | Descripción |
|---|---|---|
Nop | 255 | Sin operación |
Objetos de Función
Sección titulada «Objetos de Función»Cada función compilada produce un struct Function en el heap:
Function { name: String, // para depuración arity: u8, // conteo de parámetros 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>, // número de línea por instrucción}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)
Sección titulada «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 × u64 LE (limbs Montgomery) 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 la VM, que deserializa en objetos del heap.
Disposición de Variables Globales
Sección titulada «Disposición de Variables Globales»Índice: 0..22 23.. Nativos Globales de usuarioLos 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).
Archivos Fuente
Sección titulada «Archivos Fuente»| Componente | Archivo |
|---|---|
| Opcodes | vm/src/opcode.rs |
| Intérprete VM | vm/src/machine/vm.rs |
| Frames de llamada | vm/src/machine/frame.rs |
| Despacho de nativos | vm/src/specs.rs |
| Codificación de valores | memory/src/value.rs |
| Struct Function | memory/src/heap.rs |
| Compilador de bytecode | compiler/src/codegen.rs |
| Compilador de funciones | compiler/src/function_compiler.rs |
| Serializador binario | cli/src/commands/compile.rs |
| Cargador binario | vm/src/loader.rs |