Skip to main content
Ant is a lightweight JavaScript runtime built from the ground up with a custom VM, efficient memory management, and full async/await support. The runtime is designed to be compact yet powerful, providing modern JavaScript features in a small footprint.

Core architecture

The Ant runtime consists of several key components that work together:

Silver VM

At the heart of Ant is the Silver VM, a custom JavaScript execution engine that compiles and runs JavaScript code. The VM supports two execution modes:
  • SV_VM_MAIN - Standard synchronous execution
  • SV_VM_ASYNC - Async function execution with suspend/resume capabilities
The VM uses a bytecode compiler that transforms JavaScript source into optimized bytecode, which is then executed by the interpreter.
// VM creation from runtime.c
sv_vm_t *sv_vm_create(ant_t *js, sv_vm_kind_t kind);

NaN-boxing value representation

Ant uses NaN-boxing to efficiently represent JavaScript values in 64 bits. This technique stores type information in the unused bits of IEEE 754 NaN values:
// From ant.c - value types
typedef enum {
  T_UNDEF, T_NULL, T_BOOL, T_NUM, T_BIGINT, T_STR,
  T_SYMBOL, T_OBJ, T_ARR, T_FUNC, T_CFUNC, T_CLOSURE,
  T_PROMISE, T_GENERATOR, T_PROP, T_ERR, T_TYPEDARRAY,
  T_FFI, T_NTARG
} value_type_t;
This design allows Ant to represent all JavaScript types efficiently without additional heap allocations for primitives.

Memory management

Arena allocator

Ant uses an arena-based memory allocator for managing JavaScript objects and values. The allocator maintains a continuous block of memory that grows as needed:
// From runtime.c - code arena allocation
const char *code_arena_alloc(const char *code, size_t len);
void *code_arena_bump(size_t size);
The arena allocator provides:
  • Fast allocation with simple pointer bumping
  • Efficient memory reuse
  • Mark-and-sweep garbage collection
  • String interning to reduce memory usage

Garbage collection

Ant implements a conservative mark-and-sweep garbage collector that:
  1. Marks all reachable values starting from roots
  2. Sweeps unreachable values to reclaim memory
  3. Runs automatically when memory pressure is detected
// GC is triggered automatically
if (js->needs_gc) js_gc_maybe(js);

Runtime initialization

The runtime is initialized with process information and global objects:
// From runtime.c
struct ant_runtime *ant_runtime_init(
  ant_t *js, 
  int argc, 
  char **argv, 
  struct arg_file *ls_p
) {
  runtime = (struct ant_runtime){
    .js = js,
    .ant_obj = js_newobj(js),
    .flags = 0, 
    .argc = argc, 
    .argv = argv,
    .pid = (int)ant_getpid(),
    .ls_fp = (ls_p && ls_p->count > 0) ? ls_p->filename[0] : NULL,
  };

  jsval_t global = js_glob(js);
  js_set(js, global, "global", global);
  js_set(js, global, "window", global);
  js_set(js, global, "globalThis", global);
  js_set(js, global, "Ant", runtime.ant_obj);

  return &runtime;
}

Built-in modules

Ant provides a comprehensive set of built-in modules that are initialized at startup:
// From main.c - module initialization
init_symbol_module();
init_date_module();
init_regex_module();
init_collections_module();
init_builtin_module();
init_buffer_module();
init_fs_module();
init_atomics_module();
init_crypto_module();
init_fetch_module();
init_console_module();
init_json_module();
init_server_module();
init_timer_module();
init_process_module();

Stack management

Ant carefully manages the call stack to prevent overflow:
// From main.c - stack limits
volatile char stack_base;
js_setstackbase(js, (void *)&stack_base);

struct rlimit rl;
if (getrlimit(RLIMIT_STACK, &rl) == 0 && rl.rlim_cur != RLIM_INFINITY)
  js_setstacklimit(js, (size_t)rl.rlim_cur * 3 / 4);
else
  js_setstacklimit(js, 512 * 1024);

Execution modes

Ant supports multiple execution modes:

Script execution

# Execute a JavaScript file
ant script.js

Module execution

# Execute an ES module
ant module.mjs

REPL mode

# Interactive REPL
ant

Eval mode

# Evaluate code directly
ant -e "console.log('Hello')"
ant -p "2 + 2"  # Print result

Performance considerations

JIT compilation

The Silver VM includes an optional JIT compiler that can optimize hot code paths. Enable JIT debugging with:
export ANT_DEBUG="dump/vm:jit"

Memory optimization

Ant uses several techniques to minimize memory usage:
  • String interning: Duplicate strings share the same memory
  • Rope strings: Large string concatenations use rope data structures
  • Packed arrays: Dense arrays are stored efficiently
  • Property caching: Property lookups are cached for fast access
Use --stack-size=<kb> to adjust the VM stack size for deeply recursive code.

Error handling

The runtime provides comprehensive error handling with stack traces:
// From main.c - error handling
if (print_uncaught_throw(js)) {
  js_result = EXIT_FAILURE;
  return;
}
Errors include:
  • File location and line numbers
  • Stack traces for debugging
  • Type information for invalid operations

Next steps

Event loop

Learn about async execution and the event loop

Module system

Understand ESM and built-in modules

Build docs developers (and LLMs) love