RPNXCortado
C++23 JVM class-file, bytecode, validation, and JAR toolkit
Loading...
Searching...
No Matches
Exact instructions and the constant pool

Code generators can mix Cortado's symbolic conveniences with exact wire-level instruction alternatives. The distinction is about who chooses indexes, widths, and padding.

Prefer symbolic operations for relocatable code

The symbolic operations are intended for ordinary compiler lowering:

  • iload, istore, and the other local operations choose compact, ordinary, or wide encodings;
  • ldc_string interns both constants and chooses ldc or ldc_w;
  • field, method, and class operations intern compatible constant kinds;
  • symbolic branches widen without exposing displacements; and
  • switches recalculate padding from their final offsets.

Operand-free instructions use the compile-time form:

code.append< rpnx::cortado::opcode::iconst_1 >()
.append< rpnx::cortado::opcode::ireturn >();

The constraint rejects operand-bearing opcodes at compile time.

Append an exact encoding

Use append(instruction) when encoding has already been selected or when an opcode has no symbolic convenience. Exact operands refer to the class builder's shared pool:

builder.constant_pool().add_string("exact width");
rpnx::cortado::opcode::ldc_w >{message})
.append< rpnx::cortado::opcode::areturn >();
An owning symbolic JVM code builder.
Definition builders.hpp:356
A two-byte constant-pool-index instruction.
Definition bytecode.hpp:100
A type-safe index into a JVM constant pool.
Definition types.hpp:34

This deliberately retains ldc_w even when the index would fit in ldc. Likewise, exact switch instructions include their padding bytes, and exact branches contain signed displacements rather than labels. Use those forms for lossless transformations, disassemblers, assemblers with their own layout engine, and format tests—not for relocatable symbolic code.

Deterministic interning

constant_pool_builder preserves first-insertion order and returns the existing index when an equal entry is interned again. Convenience operations recursively intern their dependencies. For example, add_methodref interns the owner class, name, descriptor, NameAndType, and final method reference.

Indexes are JVM logical indexes. They begin at one, and a long_constant or double_constant occupies two logical slots even though entries() contains only one variant value for it. entry_at rejects zero, out-of-range indexes, and reserved second slots; utf8_at additionally requires a UTF-8 entry.

Use intern for exact constants that do not have a convenience function:

builder.constant_pool().intern(
A CONSTANT_Integer entry represented by its exact IEEE/JVM bits.
Definition types.hpp:95

Integer and floating constants store exact bits. This preserves signed values, NaN payloads, and round trips without host conversion.

Decode and inspect exact instructions

deserialize_instructions returns an instruction_sequence in strict mode. Each element is one alternative of the exhaustive instruction variant. instruction_opcode reads its opcode, while instruction_size includes offset-dependent switch padding.

For runtime opcode dispatch that still preserves compile-time instruction types, use visit_instruction_type. Its visitor receives std::type_identity<Instruction> for the matching alternative and the function returns false for byte values with no modeled opcode.

Tooling mode can return raw_code when an unknown opcode makes subsequent instruction boundaries unknowable. Do not mix that preservation path with new symbolic code; retain or replace the complete raw method body.

Next: Transform classes and package a JAR.