Features

What SuperJ gives you

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

Extreme development speed, at or exceeding C performance

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.

76%
of 59 benchmarks vs C — wins or ties
515K
req/s on the HTTP server — wrk is the bottleneck, not the server
11.7×
faster than Java on inverted-index search
  • repl

    Built-in REPL

    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.

  • ide

    IntelliJ IDEA plugin

    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.

  • ai-native

    AI-agent guide in the tree

    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.

  • java-shaped

    LLMs already know the syntax

    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.

terminal
$ 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

Arena memory — deterministic, no collector

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.

arena.sj
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
}
  • global arena

    Default allocation

    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 blocks

    Scoped & checked

    arena temp { … } — dropped at block exit. Escape is a compile error, statically checked. Lexical, not dynamic.

  • local

    Stack allocation

    local Point p = new Point(...) lowers to alloca — for the hot, bounded case you opt into.

  • no destroy()

    Arena drop is the reclamation

    No finalize(), no destroy(). File handles close(), crypto keys zeroize(), DirectArray free() — the rest is arena drop.

Backend

AOT to native — no VM, no JIT, no runtime to ship

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.

  • llvm

    Optimized machine code

    Straight to -O3 native code through LLVM 22. Optional --enterprise whole-program LTO across SDK + user code.

  • self-hosted

    Compiler in SuperJ

    The superj binary is produced by SuperJ — the toolchain builds itself, end to end.

  • targets

    macOS & Linux

    macOS arm64 (kqueue), Linux x86_64 and aarch64 (epoll). One binary per target — copy and run.

  • flags

    Tune the codegen

    --no-bounds-check, --simd=avx2, --target-cpu=native, --debug. The max-perf recipe is one line.

Concurrency model

Single-threaded by design — scale with processes

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.

scale.sj
// 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
  }
}
  • no locks

    No data races

    One thread means no locks, no atomics in user code, no cross-core cache ping-pong on the hot path.

  • determinism

    Replay is bit-for-bit

    Same event sequence → same state. Bugs reproduce. Tests aren't timing-dependent. The SEDA sequencer is the single ordering authority.

  • SEDA

    Total-order events

    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.

  • the math

    Three impossibility results

    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

Low-level control Java keeps out of reach

Beyond the arena model, SuperJ adds the primitives you'd otherwise drop to C for — with the type system still watching your back.

  • local

    Stack allocation

    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.

  • layout

    Fixed-layout structs

    Header-less value types with a known wire layout. view(buf, off) flyweight over bytes — zero-copy protocol code.

  • arrays

    Rectangular arrays

    int[,] / int[,,] — contiguous, stride-indexed, a distinct type from jagged int[][].

  • interop

    Native C / Rust

    native methods call straight into the C ABI — no JNI, no marshalling layer. Direct symbol resolution at link time.

  • strings

    UTF-8 by construction

    One string/String type, byte[]-backed, length-prefixed and NUL-terminated — a valid C string zero-copy.

Crypto-grade numerics

Wide integers and SIMD — first-class, not a library

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.

crypto.sj
// 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
  • i128 / i256 / i512

    Native wide integers

    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.

  • SIMD

    First-class vector intrinsics

    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.

  • auto-vec

    Auto-vectorization on top

    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

A deliberate ledger

Every removal buys predictability; everything kept is what made Java productive in the first place.

✗ Removed from Java

  • // threads, synchronized, volatile
  • // tracing garbage collector
  • // reflection & class loading
  • // lambdas & closures
  • // autoboxing / unboxing
  • // non-static inner classes
  • // checked exceptions, modules, finalize()
  • // labeled break/continue, switch pattern matching

✓ Kept from Java

  • // classes, interfaces, inheritance
  • // generics with erasure + wildcards
  • // enums & anonymous classes
  • // exceptions (all unchecked)
  • // varargs & method references ::
  • // instanceof pattern matching
  • // familiar control flow & syntax
  • // String / string, one immutable type

SDK

Batteries-included systems SDK

Every package is under sj.*. Discover the full API with superj doc --list and superj doc <class-fqn>.

PackageWhat
sj.langString, StringBuilder, Math, Integer, System
sj.utilcollections & hash, primitive-specialized (IntArrayList, Int2IntMap, ByteSet…), random, base64, bit utils
sj.ioFile, FileReader/Writer, DirectArray, mmap
sj.httpincremental HTTP/1.1 + HTTP/2 server, TLS 1.3, cookies, content types, routing, static files, WebSockets
sj.jsonhand-written incremental JSON parser
sj.sedathe event-driven framework (Apps → Sequencer → event queue)
sj.cryptoSHA256 (ARM NEON), Secp256k1, EthereumAddress, EIP-712, TLS engine
sj.netNioAdapter event loop (TCP/UDP/Unix, epoll/kqueue), UnixGateway
sj.testAsserts, 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

The linkable ecosystem is the compiled 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

Determinism is the stronger property

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.

Read the memory-safety note →