Features
SuperJ keeps the parts of Java that make it pleasant and productive, drops the parts that fight predictable native performance, and adds a layer of systems-level capability Java doesn't have. The result reads like Java but behaves like C.
The headline feature
Every design decision in SuperJ — the Java syntax, the deterministic execution, the claim layer, the self-hosted compiler — serves one thesis: an AI agent that writes code needs a language that makes wrong code either impossible, caught at compile time, or trivially reproducible and fixable. SuperJ is engineered end-to-end for that. Here are the five key enablers:
SuperJ is Java-shaped: classes, generics, exceptions, method references. Every LLM trained on public code already knows the syntax. An agent writes correct SuperJ on the first try — the deltas (arena blocks, local, no lambdas) are small, listed in one scannable page, and documented in the agent guide. No new syntax to learn, no fine-tuning required.
Single-threaded execution, arena memory, no GC pauses, no JIT deoptimization, no reflection. The program that runs today is the program that runs tomorrow — byte-for-byte. When an agent's code is wrong, the failure is reproducible: same input, same output, same crash, every time. No heisenbugs, no race conditions, no "works on my machine." Determinism is the strongest correctness property an agent can have — every bug is reproducible and fixable, not just one class of bug prevented.
Capabilities (net, fs.read), architecture rules (import boundaries), and contracts (pure, noalloc, requires, ensures) — all compiler-enforced, zero runtime cost in release. An agent can't go rogue: if it writes network code in a package that holds no net capability, the compile fails. The claim layer is the guardrail that lets you hand an agent the keys and know exactly what it can and cannot do. See The Claim Layer.
The superj compiler is comprehensive, fast, and self-hosted — built in SuperJ, not a foreign toolchain. It catches wrong code at compile time: type errors, arena escape, uninitialized locals, missing capabilities, contract violations. Every diagnostic is located and actionable. The compiler is the agent's pair programmer: it stops misbehavior before the code ever runs. And because it's self-hosted, the agent can read, modify, and extend the compiler itself — the toolchain is not a black box.
Every distribution ships AGENTS.md plus a topic-graph of focused agents/*.md files (types, memory, classes, SIMD, native, SDK, build, gotchas) — the same material a human contributor reads, written for both. The build is whole-program and reproducible: superj build from the same source always produces the same binary. An agent can scaffold a project, write a handler, wire up the SDK, compile to native, run tests, and verify the output — all without a human typing a line.
Why this is the headline. For seventy years, language design asked what makes a human programmer happy. That assumption has broken. What does a language look like when its primary user is a machine that is confidently, plausibly, and frequently wrong — and why does Rust, the strongest "looks right but isn't" detector ever built, paradoxically make agents struggle? The answer is: agents need legibility (Java syntax they already know), reproducibility (determinism so bugs are reproducible), and guardrails (the claim layer so they can't misbehave). SuperJ is engineered for exactly that. Read the full argument: The Pursuit of Agentic Happiness →
No VM. No JIT. No surprises.
Why SuperJ
The core promise: write at Java speed, run at C speed — or faster. No JVM warm-up, no GC pauses, no JIT deoptimization, no borrow-checker tax. A single self-contained native binary from the same source a Java developer already knows how to read. Across 54 head-to-head benchmarks, SuperJ wins or ties 78% — and beats C by up to 2.57× on SIMD matmul, 10.4× on i512 division, and 7× on adversarial hash-map keys. That's the floor: native performance is the baseline, not the ceiling.
A JIT-backed read-eval-print loop (LLVM ORC JIT host) for exploring expressions, testing SDK calls, and prototyping handlers interactively. superj repl — evaluate a snippet, see the result, no compile-link cycle.
Syntax highlighting, Go-to-Declaration, and run configuration — shipped under plugins/intellij/. Develop SuperJ in the IDE you already use; the plugin is optional but there from day one.
$ superj repl
superj> i256 x = 6i256;
superj> x * x + 1i256
res0 = 37
superj> Hash.sha256("hello")
res1 = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
superj> arena t { int[] a = new int[1024]; System.out.println(a.length); }
1024
Write at Java speed. The syntax is Java — classes, generics, exceptions, method references — so a Java developer (or an LLM trained on Java) is productive on day one. The REPL and the IntelliJ plugin mean the inner dev loop is instant. The agents/ topic graph is the same material a human contributor reads — an LLM with repo access can scaffold a project, write a handler, wire up the SDK, and compile to native without a human typing a line of tutorial. Run at C speed. AOT to LLVM -O3, arena memory with no GC pauses, and first-class SIMD/wide-integer/auto-vectorization primitives put SuperJ at or above C across the benchmark suite. That's the whole idea: reads like Java, behaves like C — hence super Java. Get started →
Memory
No tracing garbage collector. new allocates from an arena. A global arena lives for the whole program; lexical arena {} blocks are reclaimed in one O(1) drop when the block exits — no scan, no pause. A reference that would outlive its arena is a compile error, not a use-after-free.
Node createNode(int v) {
return new Node(v); // global arena — safe to return
}
void process() {
arena temp {
Buffer buf = new Buffer(1024); // in temp
// outer = buf; ← compile error: escapes its arena
} // temp dropped: buf freed, O(1)
}
void stack() {
local Point p = new Point(1,2); // stack-allocated
}
A new outside any arena block allocates from the global arena — safe to return, store, hand to C. Reclaimed by the OS on process exit.
arena temp { … } — dropped at block exit. Escape is a compile error, statically checked. Lexical, not dynamic.
local Point p = new Point(...) lowers to alloca — for the hot, bounded case you opt into.
No finalize(), no destroy(). File handles close(), crypto keys zeroize(), DirectArray free() — the rest is arena drop.
Backend
SuperJ compiles to LLVM IR and then to a single self-contained native binary. No bytecode, no class loading, no JIT warm-up. Full speed from request one. The compiler is entirely built by SuperJ itself — we dogfood our own toolchain.
Straight to -O3 native code through LLVM 22. Optional --enterprise whole-program LTO across SDK + user code.
The superj binary is produced by SuperJ — the toolchain builds itself, end to end.
macOS arm64 (kqueue), Linux x86_64 and aarch64 (epoll). One binary per target — copy and run.
--no-bounds-check, --simd=avx2, --target-cpu=native, --debug. The max-perf recipe is one line.
Concurrency model
Threads, locks, synchronized, volatile, and the Java memory model are gone. One event loop, one thread, one causal story — deterministic by construction. Scale across cores by running more processes on SO_REUSEPORT; coordinate across processes with the SEDA sequencer's total-order event stream.
// one process, one core — scale by running more copies:
// for i in 1 2 3 4; do ./webserver 8080 & done
// the kernel balances connections across them (SO_REUSEPORT)
public class WebServer {
public static void main(String[] args) {
NioConfig cfg = new NioConfig(..., true, ...);
NioAdapter a = new NioAdapter(cfg);
a.open("127.0.0.1", 8080, provider);
while (true) { a.poll(0); } // one loop, one thread
}
}
One thread means no locks, no atomics in user code, no cross-core cache ping-pong on the hot path.
Same event sequence → same state. Bugs reproduce. Tests aren't timing-dependent. The SEDA sequencer is the single ordering authority.
Apps own their state; a single Sequencer drains command queues, stamps a monotonic seq, writes one event queue. Consistency is a property of the sequence, not the scheduler.
Undecidable deadlock freedom, FLP, CAP — the trade is not avoidable. SuperJ pays it upfront in one visible place instead of across thousands of hidden lock acquisitions.
Systems reach
Beyond the arena model, SuperJ adds the primitives you'd otherwise drop to C for — with the type system still watching your back.
The local keyword lowers new to alloca — the object lives on the stack, zero heap allocation. For the hot, bounded case you opt into: scratch buffers, hash accumulators, per-call contexts. Paired with arena blocks, a request handler can serve with zero allocation on the hot path. No GC pause, no allocation pressure, no escape analysis guessing.
Header-less value types with a known wire layout. view(buf, off) flyweight over bytes — zero-copy protocol code.
int[,] / int[,,] — contiguous, stride-indexed, a distinct type from jagged int[][].
native methods call straight into the C ABI — no JNI, no marshalling layer. Direct symbol resolution at link time.
One string/String type, byte[]-backed, length-prefixed and NUL-terminated — a valid C string zero-copy.
Crypto-grade numerics
Modern cryptography, big-int math, and numeric kernels need primitives Java simply doesn't have. SuperJ ships them as native types and keywords — lowered by LLVM to the same machine instructions a C compiler emits, then auto-vectorized on top.
// i128 / i256 / i512 — signed native primitives, not structs
i256 x = 6i256;
i256 y = x * x + 1i256;
i256 q = y / 3i256; // strength-reduced to limb udiv (#1638)
// secp256k1 scalar arithmetic lives here — one i256 mod-n
// is a single LLVM sdiv, not a 4-limb hand-rolled loop.
local byte[] h = new byte[32]; // stack — no heap alloc
Hash.sha256(msg, 0, msg.length, h, 0);
// SIMD — no new syntax, just typed arrays
float[4] a = ..., b = ..., c = new float[4];
Simd.addFloat4(a, 0, b, 0, c, 0); // NEON / AVX2 / SSE2
First-class signed primitives — not library structs. Arithmetic lowers to native LLVM add/mul; division by a constant is strength-reduced to limb udiv + umulh. Essential for modern crypto: secp256k1, AES-GCM, EIP-712, SHA-3 all operate on 256-bit values natively. i256 general division is 3.4× faster than C; i512 division is 10.4× faster; i512 divide-by-constant is 1483× faster — clang still calls __divti3, SuperJ emits the strength-reduced limb sequence.
Portable vector families (Byte16, Float4, Float8, Double2, …) lowered to native SSE2 / AVX2 / NEON IR — no new syntax, just typed arrays. Simd.addFloat4, Simd.fmaFloat8, Simd.dotFloat8 — arithmetic, bitwise, compare, masked blend, convert, reduce, gather/scatter, dot, prefix-sum. On ARM NEON is baseline and always on; on x86 select --simd=sse2|avx2.
First-class cdouble (128-bit) and cfloat (64-bit) primitives — two floats packed as one type. Arithmetic (+ - * /), ==/!=, and a full ComplexMath SDK class (exp, log, sqrt, sin/cos/tan, abs, arg, conj, …) over C99 <complex.h>. Imaginary literals: 3.0i, 2.5fi.
Even scalar loops get vectorized. LLVM -O3 auto-vectorizes the SuperJ IR directly: the HNSW byte-L2 distance loop compiles to usubl.8h/smlal.4s/ldp q NEON (32 bytes per iteration) with no explicit intrinsics. A cache-blocked tiled GEMM with local float[4] accumulators beats C's auto-vectorizer by 1.15-2.57× at every matrix size — register-resident accumulators give both register reuse and cache locality, while C's streaming approach gets only one.
Why it matters. A language that wants to do crypto and numeric kernels at native speed needs these primitives at the type-system level, not as a library. Java's BigInteger allocates per operation and boxes every value; Rust's u256 is a library struct with method-call dispatch. SuperJ's i256 is an LLVM IR type — the backend decomposes it into 2×128-bit GPRs or AVX-512 zmm registers, and the optimizer treats it like any other integer. That's why the wide-integer benchmarks match C on add/mul and beat it by 3-1483× on division.
GPU & AI
The sj.gpu stack puts Metal, CUDA, and a CPU reference backend behind one API — same code, same results. Load a GGUF model, prefill, decode: forty lines, faster than llama.cpp on Apple Silicon.
sj.gpu — Metal / CUDA / CPUOpen a GpuDevice, load a quantized model (Model.load), run prefill + decode with a KvCache. Metal on Apple Silicon, CUDA on NVIDIA, and a CPU reference backend everywhere else — identical code, bit-for-bit results. See Writing an LLM Inference Engine.
Beneath the high-level API: a Tensor layer for custom model architectures — quantized matmul, attention, RoPE, all as GPU kernels. The same stack that outruns llama.cpp.
Architecture & contracts
Declare what each package may do (capabilities), what it may import (architecture), and what its methods must guarantee (contracts) — the compiler holds every line to it. Zero runtime cost in release builds.
One line in Build.sj: capabilities = { "myapp", "net, fs.read" }. Default-deny: any package not listed holds no capabilities. superj capabilities shows granted vs. used — tighten until they match. See The Claim Layer.
Declare which packages may import which — enforce layering at compile time. No more "util depends on everything" rot.
pure, noalloc, requires, ensuresOne-word method claims: pure (no side effects), noalloc (no allocation). Pre/postconditions with requires/ensures — checked in debug, erased from release binaries.
The trade
Every removal buys predictability; everything kept is what made Java productive in the first place.
synchronized, volatilefinalize()::instanceof pattern matchingString / string, one immutable typeSDK
Every package is under sj.*. Discover the full API with superj doc --list and superj doc <class-fqn>.
| Package | What |
|---|---|
| sj.lang | String, StringBuilder, Math, Integer, System |
| sj.util | collections & hash, primitive-specialized (IntArrayList, Int2IntMap, ByteSet…), random, base64, bit utils |
| sj.io | File, FileReader/Writer, DirectArray, mmap |
| sj.http | incremental HTTP/1.1 + HTTP/2 server, TLS 1.3, cookies, content types, routing, static files, WebSockets |
| sj.json | hand-written incremental JSON parser |
| sj.seda | the event-driven framework (Apps → Sequencer → event queue) |
| sj.crypto | SHA256 (ARM NEON), Secp256k1, EthereumAddress, EIP-712, TLS engine |
| sj.net | NioAdapter event loop (TCP/UDP/Unix, epoll/kqueue), UnixGateway |
| sj.test | Asserts, the unit-test harness, golden-output suite |
No autoboxing — List<int> is a compile error. Use the primitive-specialized collections for int/long/byte keys and values; the generic ArrayList<E> / HashMap<K,V> for reference types. The SDK links in three variants — community (archive), enterprise (LTO), vip (source) — see Download.
Ecosystem
SuperJ is an LLVM language, so the compiled C-ABI core of every LLVM language's ecosystem (Rust, C, C++, Zig, Swift) links via native for free: crypto (ring, BoringSSL, libsodium), compression (zstd, lz4, brotli), numerical kernels (BLAS/LAPACK), parsers, system bindings. The source-ergonomic layer (derive macros, async desugaring) doesn't cross any language boundary — not even to C — and the SuperJ SDK covers the Java-ergonomic gap (collections, JSON, HTTP) so you rarely miss it.
Safety
SuperJ doesn't have a borrow checker. The one bug class it makes impossible isn't worth the permanent per-line tax for most software. Instead, single-threaded + SEDA gives you determinism: every bug reproducible and fixable, no timing-dependent behavior, no timing attack surface. Memory safety is a negative property obtained by introducing nondeterminism; determinism closes the larger hole by construction.