Master the fundamental concepts of jvm internals through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksRunning \`Hello World\` on a toy JVM requires class parsing, constant pool resolution, and a bytecode interpreter for a handful of opcodes. Real HotSpot adds tiers, GC, and intrinsics; the core loop is the same fetch-decode-execute pattern as your bytecode VM.
Minimum capabilities:
Native methods (\`System.out\`) can be stubbed: when bytecode hits \`getstatic\` on \`out\`, return a handle your runtime recognizes.
For example, \`getstatic java/lang/System.out\` followed by \`ldc "Hello"\` and \`invokevirtual println\` is the entire program path.
Frame setup mirrors the JVM spec: local array sized from \`max_locals\`, operand stack from \`max_stack\`.
Stub native methods with logging first so you know which host calls fire during Hello World. Real JVMs map hundreds of natives; a toy runtime can fake `println` with a single special case.
This exercise asks you to implement a minimal JVM that loads one class and runs \`main\`. You will parse enough of the class file and interpret enough opcodes to print Hello World.
You will use the same mental model here when reading production interpreter source later in the track. Sketch one concrete input on paper, predict the outcome, then confirm with code. That discipline catches logic errors early and makes debugging far faster when you extend the implementation in follow-on tasks.
Build a minimal JVM interpreter that runs real bytecode:
System.out.println for ints and strings;Methods are given the same way as in the javap task.
// starts a comment.
cLoading…
The same opcodes as the javap task, executed with Java semantics:
iconst_*, bipush, sipush, ldc (an Integer or String constant).iload*/aload*, istore*/astore*, iinc.pop, dup.iadd isub imul idiv irem ineg, wrapping at 32 bits. MIN_VALUE / -1 is MIN_VALUE, and % -1 is 0.if*, if_icmp*, goto. Offsets are relative to the branch instruction.getstatic java/lang/System.out:Ljava/io/PrintStream;, invokevirtual java/io/PrintStream.println:(I)V or …(Ljava/lang/String;)V (prints a line), and invokestatic of a method of this class. Arguments are popped into the callee's locals 0, 1, …ireturn/return, which must match the descriptor's return type.Exception in thread "main" TYPE, then one \tat CLASS.METHOD(pc P) line per frame, innermost first. A tab starts each line, and P is the frame's current instruction (for callers, the invokestatic). Print at most 6 frames, then \t... N more.
java.lang.ArithmeticException: / by zero for idiv/irem by 0;java.lang.NoSuchMethodError: CLASS.NAMEDESC for an invokestatic that resolves to nothing;java.lang.StackOverflowError for a call made when 200 frames exist.VerifyError: stack underflow at METHOD PC (OP)VerifyError: ireturn in NAMEDESC (or return)VerifyError: unknown opcode 0xXX in METHOD at PCVerifyError: METHOD falls off the end of its codeVerifyError: only System.out is supported by getstaticVerifyError: operand stack overflow in METHODNAME returned [V] after N instructions, max depth D. Only the entry method's return prints this line. METHOD PC: OPNAME [stack] before each instruction (the opname padded to 14). The stack shows ints, "strings", System.out and null.run: no method NAMEDESCrun: NAMEDESC needs N int argument(s)run: NAME DESCRIPTOR [INT ARGS]method: [FLAGS] NAME DESCRIPTORbad byte: Xbad pool entry: LINEunexpected line: LINEInput:
cLoading…
Output:
cLoading…
Hidden tests cover recursion (fib), a loop printing a sum, division by zero two frames deep, runaway recursion, a missing method, MIN_VALUE edge cases, and the VerifyErrors for underflow, return mismatch, unknown opcodes, falling off the end and an unsupported getstatic.