@@ -77,14 +77,33 @@ public ClassVisitor wrap(
7777 throw new RuntimeException (e );
7878 }
7979
80+ AdviceShader adviceShader = AdviceShader .with (module .adviceShading ());
81+
82+ // Collect the muzzle references from every advice the module defines.
83+ Set <String > adviceClasses = new HashSet <>();
84+ List <Reference > allReferences = new ArrayList <>();
85+ for (Instrumenter instrumenter : module .typeInstrumentations ()) {
86+ if (instrumenter instanceof Instrumenter .HasMethodAdvice ) {
87+ Collections .addAll (
88+ allReferences ,
89+ generateReferences (
90+ (Instrumenter .HasMethodAdvice ) instrumenter , adviceShader , adviceClasses ));
91+ }
92+ }
93+
94+ String [] orderedHelpers = computeInjectedHelpers (module , allReferences , adviceClasses );
95+
8096 File muzzleClass = new File (targetDir , moduleDefinition .getInternalName () + "$Muzzle.class" );
8197 try {
8298 muzzleClass .getParentFile ().mkdirs ();
83- Files .write (muzzleClass .toPath (), generateMuzzleClass (module ));
99+ Files .write (muzzleClass .toPath (), generateMuzzleClass (module , allReferences , orderedHelpers ));
84100 } catch (IOException e ) {
85101 throw new RuntimeException (e );
86102 }
87- return classVisitor ;
103+
104+ // Set resolved helpers directly in the module's helperClassNames() so agent reads
105+ // them directly without loading the $Muzzle class.
106+ return new HelperClassNamesWriter (classVisitor , orderedHelpers );
88107 }
89108
90109 private static Reference [] generateReferences (
@@ -123,23 +142,8 @@ private static Reference[] generateReferences(
123142 }
124143
125144 /** This code is generated in a separate side-class. */
126- private byte [] generateMuzzleClass (InstrumenterModule module ) {
127-
128- AdviceShader adviceShader = AdviceShader .with (module .adviceShading ());
129-
130- // Collect the muzzle references from every advice the module defines.
131- Set <String > adviceClasses = new HashSet <>();
132- List <Reference > allReferences = new ArrayList <>();
133- for (Instrumenter instrumenter : module .typeInstrumentations ()) {
134- if (instrumenter instanceof Instrumenter .HasMethodAdvice ) {
135- Collections .addAll (
136- allReferences ,
137- generateReferences (
138- (Instrumenter .HasMethodAdvice ) instrumenter , adviceShader , adviceClasses ));
139- }
140- }
141-
142- String [] orderedHelpers = computeInjectedHelpers (module , allReferences , adviceClasses );
145+ private byte [] generateMuzzleClass (
146+ InstrumenterModule module , List <Reference > allReferences , String [] orderedHelpers ) {
143147
144148 // Injected helpers are our own classes, so they don't need to be asserted as library
145149 // references.
@@ -201,24 +205,46 @@ private byte[] generateMuzzleClass(InstrumenterModule module) {
201205 mv .visitMaxs (0 , 0 );
202206 mv .visitEnd ();
203207
204- // Generate helperClassNames() with resolved helpers for the agent to read at load time ;
205- // skip the method entirely when the module injects nothing.
206- if ( orderedHelpers . length > 0 ) {
207- MethodVisitor hv =
208- cw . visitMethod (
209- Opcodes . ACC_PUBLIC | Opcodes . ACC_STATIC ,
210- "helperClassNames" ,
211- "()[Ljava/lang/String;" ,
212- null ,
213- null );
214- hv . visitCode () ;
215- writeStrings ( hv , orderedHelpers );
216- hv . visitInsn ( Opcodes . ARETURN );
217- hv . visitMaxs ( 0 , 0 );
218- hv . visitEnd () ;
208+ return cw . toByteArray () ;
209+ }
210+
211+ /**
212+ * Rewrite a module's {@code helperClassNames()} to return the build-time-resolved helper list.
213+ */
214+ private static final class HelperClassNamesWriter extends ClassVisitor {
215+ private static final String HELPER_METHOD = "helperClassNames" ;
216+ private static final String HELPER_DESCRIPTOR = "()[Ljava/lang/String;" ;
217+
218+ private final String [] helpers ;
219+
220+ HelperClassNamesWriter ( ClassVisitor classVisitor , String [] helpers ) {
221+ super ( Opcodes . ASM7 , classVisitor );
222+ this . helpers = helpers ;
219223 }
220224
221- return cw .toByteArray ();
225+ @ Override
226+ public MethodVisitor visitMethod (
227+ int access , String name , String descriptor , String signature , String [] exceptions ) {
228+ // Drop any existing helperClassNames() - resolved version will be re-added in visitEnd.
229+ if (HELPER_METHOD .equals (name ) && HELPER_DESCRIPTOR .equals (descriptor )) {
230+ return null ;
231+ }
232+ return super .visitMethod (access , name , descriptor , signature , exceptions );
233+ }
234+
235+ @ Override
236+ public void visitEnd () {
237+ if (helpers .length > 0 ) {
238+ MethodVisitor mv =
239+ super .visitMethod (Opcodes .ACC_PUBLIC , HELPER_METHOD , HELPER_DESCRIPTOR , null , null );
240+ mv .visitCode ();
241+ writeStrings (mv , helpers );
242+ mv .visitInsn (Opcodes .ARETURN );
243+ mv .visitMaxs (0 , 0 );
244+ mv .visitEnd ();
245+ }
246+ super .visitEnd ();
247+ }
222248 }
223249
224250 /** Resolves the ordered set of helper classes to inject for a module. */
0 commit comments