Systems language · AOT · LLVM · self⁠-hosted

superJ

Reads like Java.
Behaves like C. //

A single-threaded, ahead-of-time language in the Java family — not a subset of it. No VM, no JIT, no garbage collector. Familiar classes, generics and exceptions; native speed and arena-scoped memory underneath.

0 garbage collectors 0 runtime threads compiles to native the compiler is written in SuperJ
event.sj
// Looks like Java — runs with no GC.
public class Report {
  public static void main(String[] args) {
    int total = 0;
    arena scratch {              // scoped memory
      int[] rows = new int[1<<16];
      for (int i = 0; i < rows.length; i++)
        total += (rows[i] = i * 3);
    }                             // freed here — O(1), no pause
    System.out.println(total);
  }
}

The thesis

Keep what makes Java pleasant. Drop what fights native performance.

SuperJ compiles to LLVM IR and then to machine code. There is no bytecode, no class loading, no tracing collector, and no threading — the whole program is known at compile time, so behavior is predictable down to the allocation.

Memory

Arenas, not GC

A global arena for the program, plus lexical arena {} blocks reclaimed in one O(1) drop — no stop-the-world pauses.

Backend

Native via LLVM

Straight to optimized machine code. No VM, no JIT warm-up, no runtime to ship.

Model

Single-threaded

Threads, locks, monitors and the memory model are gone — deterministic by construction.

Bootstrap

Self-hosted

The SuperJ compiler is written in SuperJ — the toolchain builds itself, end to end. We dogfood our own language.

Signature feature

Deterministic memory — and the compiler proves it's safe

Allocate short-lived objects inside an arena block; when the block exits, the whole arena is dropped at once. A reference that would outlive its arena is a compile error, not a lurking 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
    Node n = createNode(5);       // in global
    // outer = buf;  ← rejected: escapes its arena
  }              // temp dropped: buf freed, n still valid
}

Lexical, not dynamic. A new belongs to the arena it's written inside — called methods keep using the global arena unless they open their own.

arena temp { … } allocating…
temp
Buffer 1 KB
byte[] payload
Frame ×3
✓  whole arena freed in one O(1) drop — no scan, no pause

↳  n (global arena) survives the block.

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.

memory

Arena & stack scoping

arena {} for O(1) bulk reclaim; local for stack-scoped references.

numerics

Wide integers

First-class i128, i256, i512 primitives for crypto and big-int math.

layout

Fixed-layout structs

Header-free value types with a known wire layout — ideal for protocols and mmap.

arrays

Rectangular arrays

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.

functions

Method references

Class::method targets a single-abstract-method interface — capture-free, no closures.

generics

Erased generics

Class- and method-level, bounded params, and ? extends / ? super wildcards.

data-parallel

SIMD vectors

Portable vector families (Byte64, Float8, …) lowered to native SIMD IR.

safety

Definite assignment

A local read before it's assigned is a compile error — no accidental garbage reads.

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()

✓ Kept from Java

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

Proof

Native speed, flat tails

A web server on the built-in HTTP stack, compiled to a single native binary and load-tested over loopback — the server pinned to one core, the load generator to another. It serves faster than wrk can issue requests.

515K
requests / sec — wrk caps at ~423K, so it's the bottleneck
~1.1×
p99 within ~1.1× of p50 — a flat tail
0
GC pauses — arena memory, no scans

Measured on a Ryzen 9 9950X3D, single core each (server on CPU 4, client on CPU 3): SuperJ's own pipelined client reaches ~515K req/s while wrk tops out at ~423K — the load generator, not the server, is the limit. Under sustained load the server's tail stays flat — p50 156µs, p99 167µs — because there's no collector to pause on. See the full benchmarks →

One line, the whole idea

Reads like Java. Behaves like C.
Hence super Java.
Download SuperJ Read the quickstart