Class PeepholeOptimizingMethodVisitor
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.
Model
At most one pending load (constant, variable load, standaloneCHECKCAST, or Boolean.TRUE/FALSE), at most one
pending box (Wrapper.valueOf or
DefaultTypeTransformation.box(boolean)), 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:
- labels, jump targets, table/lookup switches
- stack map frames
- line numbers, local-variable tables, and type annotations
- method and
invokedynamiccalls (except matched box/unbox pairs) visitMaxs/visitEnd
Rewrites
- Constant narrowing —
LDC/push forms becomeICONST_*,BIPUSH,SIPUSH,LCONST_*,FCONST_*,DCONST_*, orACONST_NULLwhen legal. Signed floating-point zeros (-0.0f/-0.0d) are preserved via raw-bit comparison (GROOVY-9797). - Dead loads — a buffered load or constant followed by a matching
POP/POP2, or a voidRETURN, is dropped when the load is pure (no attachedCHECKCAST). A bufferedIINCpaired withILOADis retained as a side effect when the loaded value itself is discarded. - CHECKCAST — may attach to a pending
ALOADor reference constant so the cast is emitted immediately after the load on flush. When the cast result is discarded (POPor voidRETURN), the cast is always kept so a possibleClassCastExceptionremains 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, withPOPinserted before voidRETURNso the frame stays verifiable. - Compare-to-zero / null —
ICONST_0;IF_ICMP*→IF*;ACONST_NULL;IF_ACMP*→IFNULL/IFNONNULL. - DUP + store + pop —
DUP/DUP2; store; matching pop becomes a plain store; bareDUP/DUP2with a matching pop is eliminated. - Box/unbox cancellation and conversion —
Wrapper.valueOf(p)/DefaultTypeTransformation.box(p)followed by a same-type unbox (Wrapper.xxxValue()orDefaultTypeTransformation.xxxUnbox) cancel to a no-op (the primitive remains on the stack). Cross-convention pairs of the same primitive type are included (for exampleDTT.box(I)thenInteger.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 asInteger.valueOfthenLong.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 usesI2Lforlong l = intExprdirectly). Boolean is excluded from conversion rewrites (only same-type cancel applies). A boxed value discarded byPOP/POP2(or voidRETURN) drops the box and, when the primitive producer is still in the load window, drops that producer too; otherwise it pops the original primitive (POP2when wide).POP2on a narrow boxed value is treated as two one-slot discards (box/primitive plus the slot underneath). - Boolean constant folding —
GETSTATIC Boolean.TRUE/FALSEfollowed bybooleanValue()orDefaultTypeTransformation.booleanUnboxbecomesICONST_1/ICONST_0. - Big number lowering — buffered
BigDecimal/BigIntegerconstants becomenew Type(String)construction on flush.
Installation
PreferPeepholeOptimizingClassVisitor (wired from
WriterController) so every method is covered. Use wrap(MethodVisitor)
only when constructing a method visitor outside that chain (for example unit tests).
Integer constants are re-emitted through BytecodeHelper.pushConstant(org.objectweb.asm.MethodVisitor, int) on the
delegate so they are not re-buffered by this visitor.- Since:
- 6.0.0
- See Also:
-
Field Summary
Fields inherited from class org.objectweb.asm.MethodVisitor
api, mv -
Constructor Summary
ConstructorsConstructorDescriptionPeepholeOptimizingMethodVisitor(org.objectweb.asm.MethodVisitor delegate) Creates a peephole visitor that forwards compacted instructions todelegate. -
Method Summary
Modifier and TypeMethodDescriptionstatic booleanprintTraceBytecode(org.objectweb.asm.MethodVisitor visitor, PrintWriter out) Walksvisitorand any nestedPeepholeOptimizingMethodVisitorlayers to find aTraceMethodVisitor, then prints that visitor's recorded instruction text toout.voidvisitAttribute(org.objectweb.asm.Attribute attribute) voidvisitEnd()voidvisitFieldInsn(int opcode, String owner, String name, String descriptor) voidvisitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) voidvisitIincInsn(int varIndex, int increment) voidvisitInsn(int opcode) org.objectweb.asm.AnnotationVisitorvisitInsnAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, String descriptor, boolean visible) voidvisitIntInsn(int opcode, int operand) voidvisitInvokeDynamicInsn(String name, String descriptor, org.objectweb.asm.Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) voidvisitJumpInsn(int opcode, org.objectweb.asm.Label label) voidvisitLabel(org.objectweb.asm.Label label) voidvisitLdcInsn(Object value) voidvisitLineNumber(int line, org.objectweb.asm.Label start) voidvisitLocalVariable(String name, String descriptor, String signature, org.objectweb.asm.Label start, org.objectweb.asm.Label end, int index) org.objectweb.asm.AnnotationVisitorvisitLocalVariableAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, org.objectweb.asm.Label[] start, org.objectweb.asm.Label[] end, int[] index, String descriptor, boolean visible) voidvisitLookupSwitchInsn(org.objectweb.asm.Label dflt, int[] keys, org.objectweb.asm.Label[] labels) voidvisitMaxs(int maxStack, int maxLocals) voidvisitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) voidvisitMultiANewArrayInsn(String descriptor, int dims) voidvisitTableSwitchInsn(int min, int max, org.objectweb.asm.Label dflt, org.objectweb.asm.Label... labels) org.objectweb.asm.AnnotationVisitorvisitTryCatchAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, String descriptor, boolean visible) voidvisitTryCatchBlock(org.objectweb.asm.Label start, org.objectweb.asm.Label end, org.objectweb.asm.Label handler, String type) voidvisitTypeInsn(int opcode, String descriptor) voidvisitVarInsn(int opcode, int varIndex) static org.objectweb.asm.MethodVisitorwrap(org.objectweb.asm.MethodVisitor delegate) Idempotent factory: returnsdelegateunchanged when it isnullor already aPeepholeOptimizingMethodVisitor, otherwise wraps it.Methods inherited from class org.objectweb.asm.MethodVisitor
getDelegate, visitAnnotableParameterCount, visitAnnotation, visitAnnotationDefault, visitCode, visitMethodInsn, visitParameter, visitParameterAnnotation, visitTypeAnnotation
-
Constructor Details
-
PeepholeOptimizingMethodVisitor
public PeepholeOptimizingMethodVisitor(org.objectweb.asm.MethodVisitor delegate) Creates a peephole visitor that forwards compacted instructions todelegate.- Parameters:
delegate- the next method visitor in the chain (for example aMethodWriterorTraceMethodVisitor)
-
-
Method Details
-
wrap
public static org.objectweb.asm.MethodVisitor wrap(org.objectweb.asm.MethodVisitor delegate) Idempotent factory: returnsdelegateunchanged when it isnullor already aPeepholeOptimizingMethodVisitor, otherwise wraps it.Returning
nullunchanged matches the ASM contract thatClassVisitor.visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])may returnnullto skip a method body. Used byPeepholeOptimizingClassVisitor.visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])so nested or repeated wrapping does not stack multiple peephole layers.- Parameters:
delegate- the visitor to wrap, ornullto skip- Returns:
- a peephole-optimizing method visitor, or
nullwhendelegateisnull
-
printTraceBytecode
Walksvisitorand any nestedPeepholeOptimizingMethodVisitorlayers to find aTraceMethodVisitor, then prints that visitor's recorded instruction text toout.AsmClassGeneratoruses this whenvisitMaxsfails under classgen logging: the outer visitor is a peephole wrapper, so a directinstanceof TraceMethodVisitorcheck would miss the tracer sitting further down the chain.- Parameters:
visitor- the method visitor active during class generation (may be a peephole wrapper);nullis treated as “not found”out- destination for the traced bytecode listing- Returns:
trueif aTraceMethodVisitorwas found and printed;falseif none was present in the chain
-
visitAttribute
public void visitAttribute(org.objectweb.asm.Attribute attribute) - Overrides:
visitAttributein classorg.objectweb.asm.MethodVisitor
-
visitFrame
- Overrides:
visitFramein classorg.objectweb.asm.MethodVisitor
-
visitInsn
public void visitInsn(int opcode) - Overrides:
visitInsnin classorg.objectweb.asm.MethodVisitor
-
visitIntInsn
public void visitIntInsn(int opcode, int operand) - Overrides:
visitIntInsnin classorg.objectweb.asm.MethodVisitor
-
visitVarInsn
public void visitVarInsn(int opcode, int varIndex) - Overrides:
visitVarInsnin classorg.objectweb.asm.MethodVisitor
-
visitTypeInsn
- Overrides:
visitTypeInsnin classorg.objectweb.asm.MethodVisitor
-
visitFieldInsn
- Overrides:
visitFieldInsnin classorg.objectweb.asm.MethodVisitor
-
visitMethodInsn
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) - Overrides:
visitMethodInsnin classorg.objectweb.asm.MethodVisitor
-
visitInvokeDynamicInsn
public void visitInvokeDynamicInsn(String name, String descriptor, org.objectweb.asm.Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) - Overrides:
visitInvokeDynamicInsnin classorg.objectweb.asm.MethodVisitor
-
visitJumpInsn
public void visitJumpInsn(int opcode, org.objectweb.asm.Label label) - Overrides:
visitJumpInsnin classorg.objectweb.asm.MethodVisitor
-
visitLabel
public void visitLabel(org.objectweb.asm.Label label) - Overrides:
visitLabelin classorg.objectweb.asm.MethodVisitor
-
visitLdcInsn
- Overrides:
visitLdcInsnin classorg.objectweb.asm.MethodVisitor
-
visitIincInsn
public void visitIincInsn(int varIndex, int increment) - Overrides:
visitIincInsnin classorg.objectweb.asm.MethodVisitor
-
visitTableSwitchInsn
public void visitTableSwitchInsn(int min, int max, org.objectweb.asm.Label dflt, org.objectweb.asm.Label... labels) - Overrides:
visitTableSwitchInsnin classorg.objectweb.asm.MethodVisitor
-
visitLookupSwitchInsn
public void visitLookupSwitchInsn(org.objectweb.asm.Label dflt, int[] keys, org.objectweb.asm.Label[] labels) - Overrides:
visitLookupSwitchInsnin classorg.objectweb.asm.MethodVisitor
-
visitMultiANewArrayInsn
- Overrides:
visitMultiANewArrayInsnin classorg.objectweb.asm.MethodVisitor
-
visitInsnAnnotation
public org.objectweb.asm.AnnotationVisitor visitInsnAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, String descriptor, boolean visible) - Overrides:
visitInsnAnnotationin classorg.objectweb.asm.MethodVisitor
-
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
-
visitTryCatchAnnotation
public org.objectweb.asm.AnnotationVisitor visitTryCatchAnnotation(int typeRef, org.objectweb.asm.TypePath typePath, String descriptor, boolean visible) - Overrides:
visitTryCatchAnnotationin classorg.objectweb.asm.MethodVisitor
-
visitLocalVariable
public void visitLocalVariable(String name, String descriptor, String signature, org.objectweb.asm.Label start, org.objectweb.asm.Label end, int index) - Overrides:
visitLocalVariablein classorg.objectweb.asm.MethodVisitor
-
visitLocalVariableAnnotation
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) - Overrides:
visitLocalVariableAnnotationin classorg.objectweb.asm.MethodVisitor
-
visitLineNumber
public void visitLineNumber(int line, org.objectweb.asm.Label start) - Overrides:
visitLineNumberin classorg.objectweb.asm.MethodVisitor
-
visitMaxs
public void visitMaxs(int maxStack, int maxLocals) - Overrides:
visitMaxsin classorg.objectweb.asm.MethodVisitor
-
visitEnd
public void visitEnd()- Overrides:
visitEndin classorg.objectweb.asm.MethodVisitor
-