Class SafeExceptionTableMethodVisitor
A guarded region whose start and end labels resolve to the SAME bytecode offset (start_pc == end_pc)
is a degenerate exception-table entry that the JVM verifier rejects at class-load with
ClassFormatError: Illegal exception table range — the program compiles clean and only fails when it
is run. (See BUG-try-expression-with-resource-invalid-bytecode.md for the phase-7 root cause that
used to produce one.) A zero-length region contains no instruction, so it can catch nothing and its handler
is unreachable; dropping the entry is therefore behaviour-neutral AND turns would-be invalid bytecode into
a verifiable class.
This wrapper BUFFERS every visitTryCatchBlock call and FLUSHES them, in registration order, at the
top of visitMaxs (delegating to the real visitTryCatchBlock for each, then to
super.visitMaxs). Deferral is necessary — a static per-call-site start==end check would not
work — because a caller may register the exception block BEFORE placing its labels (javac-style forward
declaration), where the labels' offsets are not yet resolved. By visitMaxs every visited label IS
resolved (visitLabel precedes visitMaxs in the ASM contract), so Label.getOffset()
is valid and the degenerate entries can be dropped. Flushing in FIFO order preserves the exception-table
order (first-registered = first-match), which try/catch/finally handler priority relies on.
Installed once, in Ek9ClassWriter.toByteArray() — ASM's ClassWriter.visitMethod is
final, so the chokepoint is applied as a ClassReader -> ClassWriter filter over the finished
class instead (each method is copied through this visitor). The completeness of the chokepoint depends on the
invariant that every backend ClassWriter is an Ek9ClassWriter (never a raw
org.objectweb.asm.ClassWriter), so its filtering toByteArray runs — otherwise it is bypassed.
That invariant is guarded by Ek9ClassWriterUsageInvariantTest.
-
Field Summary
Fields inherited from class org.objectweb.asm.MethodVisitor
api, mv -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) static byte[]filterDegenerateExceptionTables(byte[] classBytes) CopyclassBytesverbatim (frames/maxs preserved — no recomputation, so no class loading is needed) except that every method is filtered throughSafeExceptionTableMethodVisitor, dropping any exception-table entry whose start and end labels resolve to the same offset.voidvisitMaxs(int maxStack, int maxLocals) voidvisitTryCatchBlock(org.objectweb.asm.Label start, org.objectweb.asm.Label end, org.objectweb.asm.Label handler, String type) Methods inherited from class org.objectweb.asm.MethodVisitor
getDelegate, visitAnnotableParameterCount, visitAnnotation, visitAnnotationDefault, visitAttribute, visitCode, visitEnd, visitFieldInsn, visitFrame, visitIincInsn, visitInsn, visitInsnAnnotation, visitIntInsn, visitInvokeDynamicInsn, visitJumpInsn, visitLabel, visitLdcInsn, visitLineNumber, visitLocalVariable, visitLocalVariableAnnotation, visitLookupSwitchInsn, visitMethodInsn, visitMethodInsn, visitMultiANewArrayInsn, visitParameter, visitParameterAnnotation, visitTableSwitchInsn, visitTryCatchAnnotation, visitTypeAnnotation, visitTypeInsn, visitVarInsn
-
Constructor Details
-
SafeExceptionTableMethodVisitor
SafeExceptionTableMethodVisitor(org.objectweb.asm.MethodVisitor delegate)
-
-
Method Details
-
filterDegenerateExceptionTables
static byte[] filterDegenerateExceptionTables(byte[] classBytes) CopyclassBytesverbatim (frames/maxs preserved — no recomputation, so no class loading is needed) except that every method is filtered throughSafeExceptionTableMethodVisitor, dropping any exception-table entry whose start and end labels resolve to the same offset. In the serialized class those offsets are always resolved. For valid code (no degenerate range) this is a faithful, normalisation-equivalent copy — the filter only ever removes would-be-invalid entries. This is THE chokepoint; see the class javadoc. -
visitTryCatchBlock
public void visitTryCatchBlock(org.objectweb.asm.Label start, org.objectweb.asm.Label end, org.objectweb.asm.Label handler, String type) - Overrides:
visitTryCatchBlockin classorg.objectweb.asm.MethodVisitor
-
visitMaxs
public void visitMaxs(int maxStack, int maxLocals) - Overrides:
visitMaxsin classorg.objectweb.asm.MethodVisitor
-