or: fpath=(/path/to/javars/completions $fpath) in .zshrc
September 6, 2026 · View on GitHub
██╗ █████╗ ██╗ ██╗ █████╗ ██████╗ ███████╗
██║██╔══██╗██║ ██║██╔══██╗██╔══██╗██╔════╝
██║███████║██║ ██║███████║██████╔╝███████╗
██ ██║██╔══██║╚██╗ ██╔╝██╔══██║██╔══██╗╚════██║
╚█████╔╝██║ ██║ ╚████╔╝ ██║ ██║██║ ██║███████║
╚════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
[JAVA, COMPILED TO BYTECODE — JIT-COMPILED, NOT WALKED — NO JVM]
"The JVM runs Java on the JVM. javars runs Java on fusevm."
Java in Rust — a Java frontend that lexes and parses Java source, lowers it
to fusevm bytecode, and runs it
on the shared three-tier Cranelift JIT — the same engine behind zshrs,
stryke, awkrs, elisp, and ruby. No bespoke VM. No JVM. No .class
files.
Table of Contents
- [0x00] Overview
- [0x01] Install
- [0x02] Usage
- [0x03] Language Features
- [0x04] Command-Line Flags
- [0x05] Architecture
- [0x06] Status & Roadmap
- [0xFF] License
[0x00] OVERVIEW
Every Java runtime in existence targets the JVM: javac emits .class
bytecode, and a JVM (HotSpot, OpenJ9, GraalVM) interprets and JIT-compiles it.
javars takes a different path — it lexes and parses Java to an AST, lowers
that AST directly to fusevm bytecode, and runs it on fusevm's compiled VM
with a Cranelift tracing JIT. javars carries no VM or JIT of its own; it is a
pure frontend over the shared engine. Highlights:
- Compiled, not tree-walked — arithmetic, comparisons, and control flow
lower to native fusevm ops (
LoadInt,Add,NumLt,JumpIfFalse, …), and everyfor/while/ enhancedforis emitted rotated — the test as an entry guard plus a conditional backward branch — which is the shape fusevm's tracing JIT needs to close a trace, so a hot loop reaches native code.java --tiersreports whether it did. - fusevm-hosted, no JVM — no local
vm.rs/jit.rs, no.classfiles, nolibjvm. The same three-tier Cranelift engine that hosts zshrs, stryke, awkrs, elisp, and ruby runs Java too.jit-disk-cachepersists native code across runs. - Java print semantics —
System.out.print[ln]lowers to a formatting builtin sobooleanprintstrue/false,doubleprints3.0, andnullprintsnull— matchingjava, not the VM's shell-flavoured default. - Java
+overloading — a strict numeric hook supplies string concatenation ("x=" + x) for the mixed operands the VM's native arithmetic does not compute, while all-numeric arithmetic stays on the JIT fast path. - Real boxed wrappers —
Integer,Long,Short,Byte,Character,FloatandDoubleare heap objects with the class and the JLS cache Java gives them, soInteger a = 127, b = 127; a == bistrueand the same pair at 128 isfalse, whileInteger a = 1000; Integer b = a; a == bstaystrue. A primitive crossing into any reference position boxes — anObjectslot, a cast, a generic, anequalsargument, a collection element or key — so((Object) 1000L).getClass().getName()isjava.lang.Longand aMapkeyed on1,1.0and1Lholds the three entries Java's holds. AString's identity is theArcit already carries, so==on two of them is the reference comparison Java's is —"ab" == "ab"istrue(one pooled literal per distinct text) while(s1 + s2) == "ab"isfalse, at no allocation and no indirection. Every arithmetic, rendering and hashing surface unboxes them, so the box is visible only where Java makes it visible. - Verified against OpenJDK — the example programs and the test corpus are
diffed byte-for-byte against a reference
java; the tests freeze that output so CI needs no JDK installed.
Covered today: locals, arithmetic, the C-style control statements,
System.out.print[ln], user-defined static methods (recursion, parameters,
value returns), String instance methods, reference arrays including
multi-dimensional (new int[n], new int[m][n], {…} and {{…},{…}}
literals, indexing, .length, and true pass-by-reference/aliasing on a
host-owned object heap), and a class/object model (fields, constructors,
instance methods, this, new, field access, single inheritance with
extends, super(…) chaining and non-virtual super.member access,
instanceof, virtual method dispatch, and toString()
overrides). Interfaces (abstract + default methods, multiple
implements, interface inheritance, polymorphic dispatch), method overloading
by parameter type (most-specific resolution for methods and constructors,
including Java's variable-arity phase so T... parameters take loose
arguments), and
type-erased generics (class Box<T>, <T> T id(T x), bounded <T extends X>, the diamond, erased library type args) all run. String.format and
System.out.printf (a Formatter subset covering %d %s %S %f %e %E %g %G %b %B %h %H %x %X %o %c, all seven -/#/+/ /0/,/( flags, width,
precision, and argument indexes), the mutable StringBuilder/StringBuffer
(the full method surface, with capacity()'s growth modeled because it is
observable), and the Arrays statics round out the stdlib essentials; the
wider standard library is the next wave (see BUGS.md). Exceptions
(throw/try/catch/finally, try-with-resources, and javars's own runtime
faults raised as catchable throwables), static fields and static { }
blocks, record types, abstract classes, and enum types — down
to per-constant state (EARTH(5.97e24)) and per-constant bodies — run too, and
main's args carries the real program arguments. An unsupported construct is
a parse or compile error rather than a silent mis-run: there is no construct
javars accepts and then runs with the wrong meaning (see BUGS.md).
A program javac itself rejects is rejected here too where javars can see it —
an undeclared name, and a class, field, method, constructor, enum constant, or
parameter declared twice, each reported at the duplicate in javac's own
wording rather than resolved silently to one of the two.
[0x01] INSTALL
git clone https://github.com/MenkeTechnologies/javars
cd javars
cargo build
# run a .java file
./target/debug/java examples/FizzBuzz.java
javars is a standalone Rust crate (an explicit empty [workspace] keeps it
independent of the meta repo). fusevm is pulled from crates.io with the jit,
jit-disk-cache, aot, and ffi features, and fancy-regex supplies the
backtracking engine behind java.util.regex. Run the tests with cargo test
(no JDK required).
Zsh tab completion
cp completions/_java /usr/local/share/zsh/site-functions/_java
# or: fpath=(/path/to/javars/completions $fpath) in .zshrc
autoload -Uz compinit && compinit
[0x02] USAGE
public class FizzBuzz {
public static void main(String[] args) {
for (int i = 1; i <= 15; i++) {
if (i % 15 == 0) {
System.out.println("FizzBuzz");
} else if (i % 3 == 0) {
System.out.println("Fizz");
} else if (i % 5 == 0) {
System.out.println("Buzz");
} else {
System.out.println(i);
}
}
}
}
$ java FizzBuzz.java
1
2
Fizz
4
Buzz
...
[0x03] LANGUAGE FEATURES
Implemented and checked against the reference java:
- Entry point —
public class Name { public static void main(String[] args) { … } }. Every other member —statichelpers,staticfields, instance fields, constructors, instance methods — is compiled too.argsis bound to the real program arguments (java Prog.java a b), and to a zero-lengthString[](nevernull) when none are passed. staticfields — one cell per class, seeded with the declared type's default and then initialized by the field initializers andstatic { … }blocks in textual order, all beforemain. Reached unqualified inside the declaring class, asC.nfrom anywhere, and through an inheriting class; compound assignment and++/--write the same cell, and the field's declared type drives/-truncation and the 32-bitintwrap.recordtypes —record Pt(int x, int y) { … }derives the final fields, the canonical constructor, an accessor per component,toString()in Java'sPt[x=1, y=2]form, and a component-wiseequalsthat follows JLS 8.10.3 per component kind —Double.compare/Float.comparefor the floating ones (so aNaNcomponent equals itself and0.0does not equal-0.0),==for the other primitives, andObjects.equalsfor a reference, which reaches the component class's ownequals. A compact constructor validates before the fields are assigned; a member the body declares itself wins over the derived one.toString()overrides, wherever a value renders —println(obj),"x " + obj,obj.toString(),String.valueOf(obj),Arrays.toString/deepToString,String.join,String.format("%s", obj)/"%s".formatted(obj), and every element of aList/Set/Mapat any depth, whatever the receiver's static type — anObject, an erasedget(), a map value. A subclass that declares none inherits its ancestor's body. The override is real code: it may print (its output comes first, before theprintlnit was rendering for) and it may throw (the throwable propagates, and no half-built text reaches the stream). A program that declares no override compiles to byte-identical bytecode.- Binary type names —
getClass().getName(), the defaultClass@hashrendering, and aClassCastException's head all spell Java's binary name for a nested declaration (Outer$Nested,A$B$Cwhen doubly nested);getSimpleName()stays the simple one. A modeled JDK type reports the JDK's own spelling, private collection classes included —java.util.ArrayList,java.util.ImmutableCollections$List12for a two-elementList.of,java.util.Arrays$ArrayList,java.util.ArrayList$SubListfor a view — and an array reports its descriptor ([I,[[Ljava.lang.String;,[LT$A;), whichgetSimpleName()decodes back toint[]. - Abstract classes —
abstract class Shape { abstract double area(); … }, withsuper(…)chaining and concrete methods that call the abstract one (resolved to the subclass's override at runtime). - Locals —
int/long/double/boolean/String/vardeclarations with optional initializers; plain and compound assignment (=,+=,-=,*=,/=,%=); post-increment / post-decrement (i++,i--). Avarrecords the type it infers, sovar i = 7; i / 2truncates andvar big = 100000; big * bigwraps — including the element type of avarenhanced-forover an array literal. - Multi-declarator declarations —
int a = 1, b = 2;in statement position, in aforinit clause, and as a field. Declarators are evaluated left to right, so a later one may read an earlier (int a = 1, b = a + 1;), and any of them may be left uninitialized (int a, b = 2, c;). The C-style array suffix binds to the declarator rather than the type, exactly as Java specifies, soint p[] = {1}, q;declares anint[]and anint— the suffix is accepted on locals, fields, and parameters (static int add(int xs[], int n)). java.lang.Object—new Object()is the fieldless root instance, with a distinct identity per allocation: it works as a lock, as a sentinel, and as a map key or set element. The methods every class inherits and does not override answer fromObject—equalsis reference identity,getClass().getName()isjava.lang.Object, andtoString()is thejava.lang.Object@<hash>form.synchronized (m) { … }runs its body after evaluating the monitor once (javars runs one thread, so the lock itself is unobservable) and throwsNullPointerExceptionfor anullmonitor.- Expressions — integer (decimal,
0x,0b, octal,_-separated) / floating / string / char / boolean literals, with JLS 3.3\uXXXXescapes translated across the whole source before it is tokenized (so an escape spells an identifier or a comment as readily as a string,\\u0041stays the two characters it is written as, and\uuuu0041is the letterA); the binary operators+ - * / %,== != < > <= >=,&& ||(short-circuiting), the bitwise& | ^(Java's non-short-circuiting logical operators on booleans), and the shifts<< >> >>>with Java's per-width distance masking; unary-,!,~, and+(which changes no bits but still applies unary numeric promotion, so"" + +'A'is"65");++/--in both prefix and postfix value position on a local, an array element, an instance field, or astatic, evaluating the index or receiver exactly once; cast expressions with Java's saturating and two's-complement narrowing conversions (a reference cast is checked against the receiver's runtime class and throwsClassCastException); parenthesised grouping; Java's+string concatenation. Acharis the 16-bit integral type it is in Java —"abc".charAt(2) + 1is 100 andc - '0'reads a digit — and takes Java's string conversion back to a one-character String wherever one applies (println,+with a String,String.valueOf, aString-method argument). A compound assignment narrows back to its target's width, sobyte b = 100; b += 100;is -56.floatis Java's 32-bit type rather than an alias fordouble: it narrows at every operation (Java rounds once at 32 bits, so the operation runs on the host rather than being computed in 64 bits and narrowed afterwards) and prints the shortest decimal that round-trips at 32 bits, so1.0f / 3.0fis0.33333334. BothtoStrings follow the specification rather than a plain shortest-round-trip search, which differs at the subnormal floor: the candidate set widens to two digits whenever the shortest form has one, soDouble.MIN_VALUEprints4.9E-324andFloat.MIN_VALUEprints1.4E-45. - Control flow —
if/else if/else,while, the C-stylefor (init; cond; update)(with comma-separated init and update clauses), the enhancedfor (T x : arr)(over an array or a collection),break,continue, andreturn(a barereturn;endsmain;return <expr>;returns a value from a method). - Arrow
switch— as an expression (int r = switch (x) { case 1, 2 -> 10; default -> { … yield v; } };) and as a statement. Multi-label arms,enum/String/intdiscriminants, athrowarm, and a block arm whoseyieldruns anyfinallyit leaves. The classic colon form, with its fall-through, still works unchanged. - Exceptions —
throw,try/catch/finally, try-with-resources, multiplecatcharms matched by class, and the modeledjava.langthrowable hierarchy (RuntimeException,IllegalArgumentException,NumberFormatException, …) supplied as an implicit prelude. A user class may extend any of them and reports its own runtime class wherever Java does —toString(),"" + e,println(e), and the uncaught report all render a nestedclass MyEx extends RuntimeExceptionasT$MyEx: message. A throw unwinds real fusevm call frames into the caller's handler; an uncaught one reports and exits non-zero. Acatchnaming a throwable javars does not model is a compile error rather than an arm that can never match. Areturn/break/continueleaving a guarded block runs thefinallyon its way out, and so does an exception raised inside acatcharm. enumtypes — constants as singletons with reference identity,name()/ordinal()/toString()/equals,values()/valueOf, unqualifiedswitchlabels, enum bodies with their own methods, andimplements. A constant may carry constructor arguments (EARTH(5.97e24)) for per-constant state, or a body (PLUS { int apply(int a, int b) { … } }) — compiled to the synthetic subclass Java specifies it as, so its override (including of the enum's ownabstractmethod) dispatches on the runtime class.- Catchable runtime faults — javars's own faults are Java exceptions rather
than aborts: an out-of-range array index, a null receiver,
Integer.parseInton junk, integral/ 0and% 0, a negative array size, and theStringindex/argument faults all raise the throwable Java raises, with Java's detail message, catchable by any supertype. Anullargument faults where Java faults rather than being coerced to"", and it faults with Java's class:Integer.parseInt(null)is aNumberFormatExceptionwhileDouble.parseDouble(null)is aNullPointerException, exactly as the JDK splits them. TheString.formatfailures — missing argument, unknown conversion, a width or precision too large for anint, and every flag combinationjava.util.Formatterrejects (%,x,%#d,%+ d,%-d) — are catchablejava.util.IllegalFormatExceptions too. intwidth — Java's 32-bitintwrapping, for operations whose operand types are staticallyint;longstays 64-bit.- Division — Java's binary numeric promotion:
int / inttruncates toward zero (7 / 2→3,-7 / 2→-3), and adoubleoperand keeps the fractional result (7.0 / 2→3.5), decided from the operands' static types.int-width division stays on fusevm's native op pair, where computing inf64is provably exact; alongdivides ini64through a builtin instead, soLong.MAX_VALUE / 2is4611686018427387903andLong.MIN_VALUE / -1wraps toLong.MIN_VALUEas JLS 15.17.2 specifies. - Static methods —
static <ret> name(<params>) { … }compiled to fusevm'sOp::Callframe ABI: parameters and locals in call-frame slots, so recursion, mutual recursion, and forward references work;voidand value returns; arity checked at compile time. Stringmethods — postfixrecv.method(args)dispatch onStringreceivers:length,isEmpty,charAt,substring,indexOf,contains,equals,equalsIgnoreCase,compareTo,compareToIgnoreCase,toUpperCase,toLowerCase,trim,startsWith,endsWith,concat,replace,repeat(chainable).compareTois not one of them for a non-Stringreceiver: every boxed primitive and every userComparabledeclares it with a different answer (the sign, the arithmetic difference, or a user body), so it dispatches on the receiver's static type and, when that is erased, on its runtime class.- Regular expressions —
split(withlimit),replaceAll,replaceFirst, andmatchesrun realjava.util.regexpatterns onfancy-regex, whose backtracking VM is what makes Java's backreferences and lookaround expressible.src/regex.rstranslates the Java source first, because the two flavours' defaults differ where it changes answers: Java's\d/\w/\s/\bare ASCII-only, its(?i)folds ASCII only, its.excludes five line terminators, and its default-mode$matches before a final one. A construct with no faithful translation (a possessive quantifier, an atomic group, a Unicode block) raisesPatternSyntaxExceptionnaming it rather than compiling into a different language. - Lambdas and functional interfaces —
() -> e,x -> e,(a, b) -> { … }, and the explicitly-typed(int a, String b) -> …. A lambda compiles to a heap closure carrying a by-value snapshot of the enclosing locals (andthis), because it outlives the fusevm call frame those locals live in — which is also what gives the enhancedforJava's per-iteration capture. The target is any interface with one abstract method, Java's own rule, so a user-declaredinterface Calc { int of(int a); }works with no registration;Runnable,Supplier,Consumer,Function,BiFunction,Predicate,Comparator,UnaryOperator/BinaryOperatorand theInt*shapes are supplied as one-method interfaces in the prelude. A functional-interface variable may hold a lambda or a class instance; the runtime-class dispatch chain routes each.return,break/continue,try/finallyandthrowall work inside a lambda body. - Method references —
String::length,Integer::parseInt,Integer::sum,Point::area,obj::method,this::method,Point::new,System.out::println. A constructor reference also names a modeled stdlib type's no-argument constructor —ArrayList::new,HashMap::new,StringBuilder::new,String::new,Object::new— which is the form aSupplier-shaped use takes. java.utilcollections —List/ArrayList/LinkedList,Deque/Queue/ArrayDeque,Map/HashMap/LinkedHashMap/TreeMap,Set/HashSet/LinkedHashSet/TreeSet, the copy constructors,Arrays.asList,List.of/Set.of, andCollections.sort/reverse/max/min. A deque reads and writes at both ends (push/pop/peek,addFirst/addLast,offer*,poll*,get*/remove*/element) and distinguishes the two empty-receiver families: theget/remove/element/popspellings throwNoSuchElementExceptionwherepeek/pollanswernull.removeIfandreplaceAllrun a predicate or operator per element and report through the receiver's shape — aList.ofrefuses before it looks at the argument, anArrays.asListruns the predicate and refuses only when something must actually go.Arrays.asListis fixed-size andList.of/Set.ofimmutable, so a structural write to one throwsUnsupportedOperationExceptionas Java's does, and neither factory answersinstanceofas the mutable kind it is not. Theoffactories also refuse anull— both one they are built from and one they are asked about, soList.of(1, null)andList.of(1, 2).contains(null)each throwNullPointerExceptionrather than holding it or answeringfalse— and an out-of-range index reports through the shape the receiver has: anArrayListraisesIndexOutOfBoundsException, an array-backedArrays.asListor longerList.ofraises theArrayIndexOutOfBoundsExceptionsubclass, and a one- or two-elementList.ofraisesIndexOutOfBoundsExceptionwith Java's other wording (Index: 5 Size: 2). They are heap objects like arrays, so reference semantics hold; the enhancedforiterates them;sortandforEachtake a lambda. A sort is a stable merge sort driven by the comparator; naming none (Collections.sort(l),l.sort(null)) orders by the element's owncompareTo, andComparator.naturalOrder/reverseOrder/comparingbuild that comparator explicitly.HashMap/HashSetiterate in Java's real bucket order —(capacity - 1) & (h ^ (h >>> 16))over a power-of-two table, reproduced exactly rather than approximated with insertion order. A membership test compares with the element's ownequals(), not with identity, solist.contains(new R(1))on arecordistrue,map.getfinds an equal key, and aSetde-duplicates equal elements — the query is the receiver and the scan stops at the first hit, which is what Java's own does. A class that overridesequalsand leaveshashCodealone is not found by aHashSet/HashMap, because it is not found by Java's either;BUGS.mdhas the boundary.Set.ofrejects a repeated element withIllegalArgumentExceptionrather than dropping it. AMapalso answers the compound methods that are defined in terms of the primitive ones —compute,computeIfAbsent,computeIfPresent,merge,replace,putAll, and the two-parameterreplaceAll— including the detail that separates them fromput: a key one of the first three adds to aHashMapis linked at the head of its hash bin whereputlinks it at the tail, so the same map filled two ways iterates in two different orders, exactly as Java's does.- Output —
System.out.println(x)/System.out.print(x)with Java value formatting. - Inline Rust FFI — a
rust { pub extern "C" fn … }block insidemaincompiles to a cached cdylib whose exported functions are callable by name (viafusevm::ffi); seeexamples/Ffi.java. - Comments —
//line,/* … */block.
[0x04] COMMAND-LINE FLAGS
| Flag | Effect |
|---|---|
FILE [args…] | Run a .java file. |
-version / --version | Print the version banner and exit. |
-h / --help | Print usage and exit. |
--dump-tokens FILE | Print the lexer token stream and exit. |
--dump-ast FILE | Print the parsed AST and exit. |
--disasm FILE | Print the lowered fusevm bytecode and exit. |
--tiers FILE | Run it, then report which fusevm execution tier took each of its chunks. |
--lsp | Speak the Language Server Protocol over stdio (completion, hover, diagnostics). |
--dap | Speak the Debug Adapter Protocol over stdio (breakpoints, stepping, locals). |
Editor tooling
java --lsp runs a read-only language server: completion and hover from the
language-reference corpus in src/reference.rs — every keyword, operator, type,
library method, throwable, functional interface, synthesized class member,
String.format conversion, and runtime builtin the build implements, each with
its signature, a description, and an example — and diagnostics from the runtime's
own parser, where a syntax error maps to a diagnostic on the reported line. The
same table generates
docs/reference.html,
so the editor and the published reference cannot drift apart.
java --dap runs a Debug Adapter over stdio: line breakpoints, single-stepping
(next / stepIn / stepOut advance to the next statement in the single main
frame), a stackTrace of the current frame, and variables inspection of
main's locals. The program is compiled with per-statement line markers only in
this mode; System.out output is captured and forwarded as output events so it
never corrupts the protocol channel.
java --version reports the targeted language level (java 21) followed by the
real engine (javars <crate-version>) and the host triple, so nothing is
misrepresented as the JDK.
Inline Rust FFI
A rust { … } block inside main embeds native Rust in a Java program:
public class Ffi {
public static void main(String[] args) {
rust { pub extern "C" fn j_triple(x: i64) -> i64 { x * 3 } }
System.out.println(j_triple(14)); // => 42
}
}
Before lexing, the block is rewritten to a __rust_compile("<base64>", line)
call; the runtime hands the base64-encoded body to fusevm::ffi, which compiles
it to a cdylib (cached by content hash) and registers its pub extern "C"
exports. A bareword call whose name is not a local resolves to an FFI export by
name — but only when the program contains a rust { … } block; without one, an
unknown call stays an ordinary unresolved reference compile error.
[0x05] ARCHITECTURE
javars contains no virtual machine or JIT of its own. The execution path
mirrors how zshrs hosts zsh and ruby hosts Ruby:
Java source → lexer → parser (AST) → lower to fusevm bytecode → fusevm VM + Cranelift JIT
│
strict numeric hook (Java `+` concat)
print builtins (Java value formatting)
| Piece | How |
|---|---|
| fusevm-hosted | No local vm.rs / jit.rs, no JVM. Java lowers to fusevm bytecode and runs on the shared three-tier Cranelift JIT; jit-disk-cache persists native code across runs. |
| Native arithmetic | Operators lower to native fusevm ops; the JIT traces hot integer loops. A strict numeric hook supplies Java's + string concatenation only for non-numeric operands. |
| Java print semantics | System.out.print[ln] lowers to a registered builtin that formats values Java-style (true/false, 3.0, null), rather than the VM's shell-flavoured PrintLn. |
[0x06] STATUS & ROADMAP
This release: main, locals (including multi-declarator statements and the
C-style array suffix, int a = 1, b[] = {2};), arithmetic / comparison / logic, Java
integer-vs-float division, the ternary ?: operator, if / while /
do-while / for / switch (with fall-through, on int and String) /
break / continue (including labeled break outer; / continue outer;) /
return, the bitwise and shift operators (& | ^ ~ << >> >>> and their
compound forms), cast expressions, ++/-- in value position, System.out/System.err print[ln], string concatenation,
user-defined static methods (recursion, parameters, value returns over
fusevm's Op::Call frame ABI), String instance methods, a first slice of the
standard library (Math.*, the Integer/Long/Double parsing, radix,
bit-twiddling (bitCount, reverse, reverseBytes, highestOneBit,
lowestOneBit, numberOfLeading/TrailingZeros, rotateLeft/rotateRight,
each answering at its declared width) and constant statics,
Boolean.parseBoolean, the Character predicates, the java.util.Objects
statics (hashCode/hash/toString/isNull/nonNull/equals/
requireNonNull/requireNonNullElse, each answering for a null where the
instance method throws), String.valueOf/join/format, String.chars/
codePoints/lines, System.out.printf, and the Arrays
statics including sort/fill/copyOf/deepToString), reference arrays including multi-dimensional
(default-valued new T[n] / new T[m][n], {…} and nested {{…},{…}} literals,
get/set indexing, .length at each level, and reference/aliasing semantics on a
host-owned object heap keyed by Value::Obj), a class/object model (instance
fields with initializers, constructors, instance methods dispatched over the
frame ABI, this, new, field access obj.f, single inheritance with extends
and super(…), the non-virtual super.method(args)/super.field access an
override uses to reach the version it overrides, instanceof over every shape
the value model names (user classes, boxed primitives, collections, arrays,
enum as Enum and record as Record) with the checked reference cast
reading that same answer, runtime-class
virtual dispatch for overrides, and
toString() overrides honoured wherever a value renders), interfaces (abstract +
default methods, multiple implements, interface extends, polymorphic
dispatch through an interface type), method overloading by parameter type
(most-specific resolution for methods and constructors, plus Java's third —
variable-arity — phase, so a T... parameter is callable with loose arguments
at every call site), type-erased
generics (class Box<T>, <T> T id(T x), bounded <T extends X>, the
diamond), static fields with static { } initializer blocks, instance
initialization in JLS 12.5 order (superclass constructor, then this class's
field initializers and bare { } blocks in textual order, then the constructor
body — so a virtual call made from a superclass constructor sees the subclass's
fields at their defaults, as Java specifies; plus the implicit super() every
constructor without an explicit chain runs, and this(…) delegation, which
runs the initializers exactly once), record
types with their derived accessors / toString / equals, abstract
classes, enum constants carrying state or bodies, and lambdas +
method references (heap closures capturing by value, dispatched through any
single-abstract-method interface), and the java.util collections
(List/Map/Set with Java's real HashMap bucket iteration order, and
List.subList as a genuine aliasing view — writes cross in both directions and
a backing list modified behind it raises ConcurrentModificationException),
arrow switch expressions with yield, and java.lang.Object
(new Object() as a lock or sentinel, plus the equals/hashCode/toString/
getClass every class inherits from it) — all verified byte-for-byte against
OpenJDK.
The object heap lives host-side in src/host.rs: Value::Obj(u32) is an opaque
handle into a frontend-owned slab of arrays and instances (the same pattern the
ruby/node/php frontends use), so identity and aliasing are real rather than
value-copied.
Next waves, in priority order:
- Streams —
.stream().map(…).filter(…),IntStream.range, thecollect/reduce/findFirstterminals. The lambdas they take already work, as do the functional interfaces'defaultcomposition methods and statics (Function.andThen,Predicate.negate,Comparator.reversed/naturalOrder/comparing). What is missing is the surface itself — the sources, the intermediate operations with Java's laziness, the terminals, andOptional. A host builtin holds&mut VMand can re-enter it (that is howforEach,sortwith a comparator, and a usertoString()already run user code), so a stream can be a host object driving each stage's closure per element; compile-time pipeline fusion is one way to build it, not a prerequisite. SeeBUGS.mdfor which callback shapes can re-enter and which cannot. Map.entrySetand the remaining collection views (List.listIterator), plus wider stdlib coverage (arecord's derivedhashCode,Collectors.toCollection). The pattern forms this line used to list —case Integer i ->,case null,whenguards — andIteratorall run; measured against the reference on openjdk 21.0.12.1.- Lazy class initialization — javars runs every class's
staticinitializers beforemain; Java runs each class's on first use.
See BUGS.md for the honest known-gaps list.
[0xFF] LICENSE
MIT — free and open source. See LICENSE.