|
RPNXCortado
C++23 JVM class-file, bytecode, validation, and JAR toolkit
|
Cortado's symbolic builder performs method-level analysis by default. The analysis is part of code_builder::finish, which class_file_builder::add_method calls with the containing class, method descriptor, flags, and version.
The builder derives the initial locals from the method descriptor and access flags. It then follows normal and exceptional control-flow edges to calculate:
long and double values;StackMapTable generation.Explicit code_build_options::max_stack or max_locals values act as requested limits. They may be larger than the analyzed requirement, but a smaller value is rejected.
For class-file major versions 50 and later, frame generation is enabled by default. Straight-line methods may need no explicit entries. Branch targets, handlers, and blocks after unconditional transfers can require entries even when source-level control flow appears simple.
Primitive verifier states merge without external information. Merging two different reference types may require the common superclass. Supply a non-owning class_hierarchy_resolver_ref backed by your compiler's type model or class path:
The referenced resolver must outlive the add_method or finish call. It is queried only when two distinct reference types actually need hierarchy knowledge. The tutorial resolver conservatively returns java/lang/Object for ArrayList and HashMap; a production resolver should return the real least common superclass for every input pair it accepts.
If no resolver is supplied and a merge needs one, finalization throws unsupported_feature_error rather than inventing a type.
Line numbers and local scopes use the same labels as branches, so layout changes cannot stale their offsets. The sumTo example attaches three source lines and three local scopes before adding the method:
An add_line_number label must identify an instruction. A local-variable scope uses an inclusive start and exclusive end; the end label may be bound directly after the final instruction. add_local_variable_type has the same shape but stores a generic field signature for LocalVariableTypeTable.
set_stack_map_table installs a complete caller-provided table and bypasses automatic frame generation. Cortado replaces its name_index with the shared pool's interned StackMapTable name but otherwise retains the frames.
Automatic dataflow can be disabled only when both method limits are explicit:
This is an expert escape hatch for externally analyzed code and legacy jsr/ret subroutines. For modern branched methods, disabling stack-map generation can produce a class the JVM rejects even when structural validation succeeds. Prefer the generic analysis path or provide an exact table.