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.
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 59 head-to-head benchmarks, SuperJ wins or ties 76% — 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.
Every SuperJ distribution ships AGENTS.md plus a topic-graph of focused agents/*.md files (types, memory, classes, SIMD, native, SDK, build, gotchas). An AI agent reads those and is immediately productive — the same material a human contributor reads, written for both.
SuperJ is Java-shaped: classes, generics, exceptions, method references. An LLM trained on Java code 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.
$ 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 this website's build agent read to produce these pages — 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.
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.
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.