A compiled .class file's constant pool is a flat, 1-indexed table
every other part of the classfile refers to by index instead of
storing values inline -- string literals, class names, and method/
field signatures all get deduplicated into one pool. A Methodref
entry (what a method-call instruction like invokevirtual actually
points at) doesn't contain a class name or method name directly --
just two indices: one pointing at a Class entry, one at a
NameAndType entry, each of which points at further Utf8 entries.
Resolving a symbolic reference means walking that whole chain.
Implement:
get_utf8(index)-- return the string value of theUtf8entry atindex; raiseValueErrorif that entry isn't aUtf8entry.resolve_class(index)-- return the binary class name aClassentry names (itsname_index, looked up viaget_utf8).resolve_name_and_type(index)-- return(name, descriptor)for aNameAndTypeentry (both looked up viaget_utf8).resolve_methodref(index)/resolve_fieldref(index)-- return{"class": ..., "name": ..., "descriptor": ...}by resolving aMethodref/Fieldrefentry'sclass_index(viaresolve_class) andname_and_type_index(viaresolve_name_and_type).
Every resolver should reject an index whose entry has the wrong tag
(e.g. calling resolve_methodref on a Fieldref index) by raising
ValueError -- a classfile parser has to validate this, not assume
the bytecode is well-formed.
Example
pool = ConstantPool([
None,
("Utf8", "Calculator"),
("Class", 1),
("Utf8", "add"),
("Utf8", "(II)I"),
("NameAndType", 3, 4),
("Methodref", 2, 5),
])
pool.resolve_methodref(6)
# -> {"class": "Calculator", "name": "add", "descriptor": "(II)I"}
Constraints
- Index
0is always invalid (the constant pool is 1-indexed). - An out-of-range index, or an index whose entry has the wrong tag
for the resolver called, must raise
ValueErrorrather than returning something silently wrong.
Real-world grounding
- HotSpot's classfile parser (where the raw constant pool bytes get
parsed into typed entries and every cross-reference's tag gets
validated -- exactly the checks this exercise's
ValueErrors model):src/hotspot/share/classfile/classFileParser.cpp - HotSpot's runtime constant pool representation and its own
resolve_*family of methods (klass_ref_at,name_ref_at,signature_ref_at, ...) that this exercise'sresolve_methodref/resolve_fieldrefmirror in spirit:src/hotspot/share/oops/constantPool.cpp
Real classfiles have a dozen more constant pool tag kinds (Integer, Float, Long, Double, String, InterfaceMethodref, MethodHandle, MethodType, InvokeDynamic, ...) and HotSpot defers full resolution of some entries until first use ("lazy" resolution) rather than doing it all at parse time -- this exercise implements the core chained-index lookup underneath every variant.