public final class PeepholeOptimizingMethodVisitor
extends org.objectweb.asm.MethodVisitor
Single-pass, stack-local bytecode compaction for methods emitted by the Groovy class generator. Inspired by Groovy++'s peephole adapters.
Upstream writers such as OperandStack and BytecodeHelper may emit
a uniform, easy-to-generate form (for example visitLdcInsn for every
integer, or box immediately after a primitive producer). This visitor rewrites
those sequences, within a single basic-block window, into the densest equivalent
JVM opcodes without a second compilation pass or a full data-flow analysis.
CHECKCAST, or Boolean.TRUE/FALSE), at most one
pending box (Wrapper.valueOf or
DefaultTypeTransformation.box), and at most one
pending DUP/DUP2 (optionally followed by a buffered
store) are held at a time. Pending state is flushed to the delegate before any
non-local boundary so control flow, frames, and debug metadata stay correct:
invokedynamic calls (except matched box/unbox pairs)visitMaxs / visitEndLDC/push forms become
ICONST_*, BIPUSH, SIPUSH, LCONST_*,
FCONST_*, DCONST_*, or ACONST_NULL when legal.
Signed floating-point zeros (-0.0f/-0.0d) are preserved
via raw-bit comparison (GROOVY-9797).POP/POP2, or a void RETURN, is dropped when the
load is pure (no attached CHECKCAST). A buffered IINC
paired with ILOAD is retained as a side effect when the loaded
value itself is discarded.ALOAD or reference
constant so the cast is emitted immediately after the load on flush.
When the cast result is discarded (POP or void RETURN),
the cast is always kept so a possible ClassCastException
remains observable — matching Java and the void-return path. Pure loads
without a cast still collapse with the pop. Standalone casts of a value
already on the stack are likewise preserved before pop/return, with
POP inserted before void RETURN so the frame stays
verifiable.ICONST_0; IF_ICMP* → IF*;
ACONST_NULL; IF_ACMP* → IFNULL/IFNONNULL.DUP/DUP2; store;
matching pop becomes a plain store; bare DUP/DUP2 with a
matching pop is eliminated.Wrapper.valueOf(p) /
DefaultTypeTransformation.box(p) followed by a same-type unbox
(Wrapper.xxxValue() or DefaultTypeTransformation.xxxUnbox)
cancel to a no-op (the primitive remains on the stack). Cross-convention
pairs of the same primitive type are included (for example
DTT.box(I) then Integer.intValue()). When the unbox
targets a different numeric primitive, the pair is rewritten to
the matching JVM conversion (I2L, L2I, I2F, …),
including cross-wrapper forms such as Integer.valueOf then
Long.longValue: after a pending box the runtime value is known to
be a properly boxed primitive, so a wrong-owner unbox cannot express a
conditional CCE path (and real classgen uses I2L for
long l = intExpr directly). Boolean is excluded from conversion
rewrites (only same-type cancel applies). A boxed value discarded by
POP/POP2 (or void RETURN) drops the box and, when
the primitive producer is still in the load window, drops that producer
too; otherwise it pops the original primitive (POP2 when wide).
POP2 on a narrow boxed value is treated as two one-slot discards
(box/primitive plus the slot underneath).GETSTATIC Boolean.TRUE/FALSE
followed by booleanValue() or
DefaultTypeTransformation.booleanUnbox becomes
ICONST_1/ICONST_0.new Type(String) construction on flush.| Constructor and description |
|---|
PeepholeOptimizingMethodVisitor(org.objectweb.asm.MethodVisitor delegate)Creates a peephole visitor that forwards compacted instructions to delegate. |
| Type Params | Return Type | Name and description |
|---|---|---|
|
public static boolean |
printTraceBytecode(org.objectweb.asm.MethodVisitor visitor, PrintWriter out)Walks visitor and any nested PeepholeOptimizingMethodVisitor
layers to find a org.objectweb.asm.util.TraceMethodVisitor, then prints that visitor's
recorded instruction text to out. |
|
public void |
visitAttribute(org.objectweb.asm.Attribute attribute) |
|
public void |
visitEnd() |
|
public void |
visitFieldInsn(int opcode, String owner, String name, String descriptor) |
|
public void |
visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) |
|
public void |
visitIincInsn(int varIndex, int increment) |
|
public void |
visitInsn(int opcode) |
|
public org.objectweb.asm.AnnotationVisitor |
visitInsnAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, String descriptor, boolean visible) |
|
public void |
visitIntInsn(int opcode, int operand) |
|
public void |
visitInvokeDynamicInsn(String name, String descriptor, org.objectweb.asm.Handle bootstrapMethodHandle, Object bootstrapMethodArguments) |
|
public void |
visitJumpInsn(int opcode, org.objectweb.asm.Label label) |
|
public void |
visitLabel(org.objectweb.asm.Label label) |
|
public void |
visitLdcInsn(Object value) |
|
public void |
visitLineNumber(int line, org.objectweb.asm.Label start) |
|
public void |
visitLocalVariable(String name, String descriptor, String signature, org.objectweb.asm.Label start, org.objectweb.asm.Label end, int index) |
|
public org.objectweb.asm.AnnotationVisitor |
visitLocalVariableAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, org.objectweb.asm.Label[] start, org.objectweb.asm.Label[] end, int[] index, String descriptor, boolean visible) |
|
public void |
visitLookupSwitchInsn(org.objectweb.asm.Label dflt, int[] keys, org.objectweb.asm.Label[] labels) |
|
public void |
visitMaxs(int maxStack, int maxLocals) |
|
public void |
visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) |
|
public void |
visitMultiANewArrayInsn(String descriptor, int dims) |
|
public void |
visitTableSwitchInsn(int min, int max, org.objectweb.asm.Label dflt, org.objectweb.asm.Label labels) |
|
public org.objectweb.asm.AnnotationVisitor |
visitTryCatchAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, String descriptor, boolean visible) |
|
public void |
visitTryCatchBlock(org.objectweb.asm.Label start, org.objectweb.asm.Label end, org.objectweb.asm.Label handler, String type) |
|
public void |
visitTypeInsn(int opcode, String descriptor) |
|
public void |
visitVarInsn(int opcode, int varIndex) |
|
public static org.objectweb.asm.MethodVisitor |
wrap(org.objectweb.asm.MethodVisitor delegate)Idempotent factory: returns delegate unchanged when it is
null or already a PeepholeOptimizingMethodVisitor,
otherwise wraps it. |
| Methods inherited from class | Name |
|---|---|
class org.objectweb.asm.MethodVisitor |
org.objectweb.asm.MethodVisitor#equals(java.lang.Object), org.objectweb.asm.MethodVisitor#getClass(), org.objectweb.asm.MethodVisitor#getDelegate(), org.objectweb.asm.MethodVisitor#hashCode(), org.objectweb.asm.MethodVisitor#notify(), org.objectweb.asm.MethodVisitor#notifyAll(), org.objectweb.asm.MethodVisitor#toString(), org.objectweb.asm.MethodVisitor#visitAnnotableParameterCount(int, boolean), org.objectweb.asm.MethodVisitor#visitAnnotation(java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitAnnotationDefault(), org.objectweb.asm.MethodVisitor#visitAttribute(org.objectweb.asm.Attribute), org.objectweb.asm.MethodVisitor#visitCode(), org.objectweb.asm.MethodVisitor#visitEnd(), org.objectweb.asm.MethodVisitor#visitFieldInsn(int, java.lang.String, java.lang.String, java.lang.String), org.objectweb.asm.MethodVisitor#visitFrame(int, int, [Ljava.lang.Object;, int, [Ljava.lang.Object;), org.objectweb.asm.MethodVisitor#visitIincInsn(int, int), org.objectweb.asm.MethodVisitor#visitInsn(int), org.objectweb.asm.MethodVisitor#visitInsnAnnotation(int, org.objectweb.asm.TypePath, java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitIntInsn(int, int), org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn(java.lang.String, java.lang.String, org.objectweb.asm.Handle, [Ljava.lang.Object;), org.objectweb.asm.MethodVisitor#visitJumpInsn(int, org.objectweb.asm.Label), org.objectweb.asm.MethodVisitor#visitLabel(org.objectweb.asm.Label), org.objectweb.asm.MethodVisitor#visitLdcInsn(java.lang.Object), org.objectweb.asm.MethodVisitor#visitLineNumber(int, org.objectweb.asm.Label), org.objectweb.asm.MethodVisitor#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int), org.objectweb.asm.MethodVisitor#visitLocalVariableAnnotation(int, org.objectweb.asm.TypePath, [Lorg.objectweb.asm.Label;, [Lorg.objectweb.asm.Label;, [I, java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn(org.objectweb.asm.Label, [I, [Lorg.objectweb.asm.Label;), org.objectweb.asm.MethodVisitor#visitMaxs(int, int), org.objectweb.asm.MethodVisitor#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String), org.objectweb.asm.MethodVisitor#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn(java.lang.String, int), org.objectweb.asm.MethodVisitor#visitParameter(java.lang.String, int), org.objectweb.asm.MethodVisitor#visitParameterAnnotation(int, java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitTableSwitchInsn(int, int, org.objectweb.asm.Label, [Lorg.objectweb.asm.Label;), org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation(int, org.objectweb.asm.TypePath, java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitTryCatchBlock(org.objectweb.asm.Label, org.objectweb.asm.Label, org.objectweb.asm.Label, java.lang.String), org.objectweb.asm.MethodVisitor#visitTypeAnnotation(int, org.objectweb.asm.TypePath, java.lang.String, boolean), org.objectweb.asm.MethodVisitor#visitTypeInsn(int, java.lang.String), org.objectweb.asm.MethodVisitor#visitVarInsn(int, int), org.objectweb.asm.MethodVisitor#wait(), org.objectweb.asm.MethodVisitor#wait(long), org.objectweb.asm.MethodVisitor#wait(long, int) |
Creates a peephole visitor that forwards compacted instructions to
delegate.
delegate - the next method visitor in the chain (for example a
org.objectweb.asm.MethodWriter or org.objectweb.asm.util.TraceMethodVisitor) Walks visitor and any nested PeepholeOptimizingMethodVisitor
layers to find a org.objectweb.asm.util.TraceMethodVisitor, then prints that visitor's
recorded instruction text to out.
AsmClassGenerator uses this when
visitMaxs fails under classgen logging: the outer visitor is a
peephole wrapper, so a direct instanceof TraceMethodVisitor check
would miss the tracer sitting further down the chain.
visitor - the method visitor active during class generation (may be
a peephole wrapper); null is treated as “not found�out - destination for the traced bytecode listingtrue if a org.objectweb.asm.util.TraceMethodVisitor was found and printed;
false if none was present in the chain Idempotent factory: returns delegate unchanged when it is
null or already a PeepholeOptimizingMethodVisitor,
otherwise wraps it.
Returning null unchanged matches the ASM contract that
org.objectweb.asm.ClassVisitor#visitMethod may return null
to skip a method body. Used by PeepholeOptimizingClassVisitor.visitMethod
so nested or repeated wrapping does not stack multiple peephole layers.
delegate - the visitor to wrap, or null to skipnull when
delegate is nullCopyright © 2003-2026 The Apache Software Foundation. All rights reserved.