Master the fundamental concepts of jvm internals through this focused micro-challenge.
\`javap -c\` disassembles \`.class\` files into JVM bytecode mnemonics. Every JDK ships it, and it is the first tool Java engineers use to verify what \`javac\` actually emitted.
Stack operations and calls dominate simple methods:
For example, \`System.out.println("hi")\` shows \`getstatic\` for the \`PrintStream\`, \`ldc\` for the string, then \`invokevirtual\` on \`println\`.
Verbose mode (\`javap -v\`) adds the constant pool, stack map tables, and line numbers for debugging.
Compare `javap -c` output before and after a one-line Java source change to see what javac actually altered. Optimizations like string concatenation lowering are visible only at bytecode level.
This exercise asks you to document sample \`javap -c\` output for a simple Java class. You will label opcodes and explain how source-level statements map to stack instructions.
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.
Write a mini javap -c. Given a class's constant pool and each method's flags, name, descriptor and raw bytecode, print the method signature in Java syntax and a disassembly in javap's layout. Branch targets are resolved to absolute offsets, and constant-pool references are annotated with // Method …, // Field …, // String ….
// starts a comment.
cLoading…
B C D F I J S Z V are byte char double float int long short boolean void.Lpkg/Name; is pkg.Name, and each leading [ adds [].(params)ret.V is only valid as a return type. Anything malformed prints bad descriptor D and skips the method.| opcodes | operands |
|---|---|
nop aconst_null iconst_m1..iconst_5, iload_n aload_n istore_n astore_n (n 0-3), pop dup iadd isub imul idiv irem ineg arraylength ireturn areturn return | none |
bipush | a signed byte |
sipush | a signed 16-bit value |
iload istore aload astore | an index byte |
iinc | an index byte and a signed byte, printed I, C |
ldc | a 1-byte pool index |
getstatic getfield invokevirtual invokespecial invokestatic new | a 2-byte pool index |
ifeq ifne iflt ifge ifgt ifle if_icmpeq..if_icmple goto | a signed 16-bit offset, relative to the instruction |
Opcode values are the standard JVM ones (iload_0 = 0x1A, iadd = 0x60, ifeq = 0x99, goto = 0xA7, invokestatic = 0xB8, …).
cLoading…
%8d: then the mnemonic. With an operand, the mnemonic is padded to 14 columns, then the operand. With a pool reference, the whole text is padded to 34 columns, then // KIND TEXT.Method, Field, String, class or int. A Methodref/Fieldref whose text starts with THISCLASS. drops that prefix. A missing entry prints // ?? no constant #N. unknown opcode 0xXX at N and truncated MNEMONIC at N end that method's listing;bad pool entry: LINE (LINE without its leading and trailing blanks, like the other messages that quote a line);bad byte: X (the rest of that line is ignored);method: [FLAGS] NAME DESCRIPTOR;unexpected line: LINE.Input:
cLoading…
Output:
cLoading…
Hidden tests cover a loop with if_icmpge/goto (a backward offset), iinc, new/dup/invokespecial, ldc of an Integer, negative sipush/bipush, getfield on this class, multi-dimensional and long/double descriptors, a missing constant, an unknown opcode, a truncated instruction, and a bad descriptor.
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 works