55
66package io .opentelemetry .javaagent .tooling .instrumentation .indy ;
77
8- import io .opentelemetry .javaagent .bootstrap .CallDepth ;
98import io .opentelemetry .javaagent .bootstrap .IndyBootstrapDispatcher ;
109import io .opentelemetry .javaagent .extension .instrumentation .InstrumentationModule ;
1110import java .lang .invoke .CallSite ;
1211import java .lang .invoke .ConstantCallSite ;
1312import java .lang .invoke .MethodHandle ;
1413import java .lang .invoke .MethodHandles ;
1514import java .lang .invoke .MethodType ;
15+ import java .lang .invoke .MutableCallSite ;
1616import java .lang .reflect .Method ;
1717import java .security .PrivilegedAction ;
1818import java .util .Arrays ;
@@ -84,20 +84,14 @@ public class IndyBootstrap {
8484
8585 MethodType bootstrapMethodType =
8686 MethodType .methodType (
87- ConstantCallSite .class ,
87+ CallSite .class ,
8888 MethodHandles .Lookup .class ,
8989 String .class ,
9090 MethodType .class ,
9191 Object [].class );
9292
9393 IndyBootstrapDispatcher .init (
9494 MethodHandles .lookup ().findStatic (IndyBootstrap .class , "bootstrap" , bootstrapMethodType ));
95-
96- // Ensure that CallDepth is already loaded in case of bootstrapAdvice recursions with
97- // ClassLoader.loadClass
98- // This is required because CallDepth is a bootstrap class and therefore triggers our
99- // ClassLoader.loadClass instrumentations
100- Class .forName (CallDepth .class .getName ());
10195 } catch (Exception e ) {
10296 throw new IllegalStateException (e );
10397 }
@@ -111,7 +105,7 @@ public static Method getIndyBootstrapMethod() {
111105
112106 @ Nullable
113107 @ SuppressWarnings ({"unused" , "removal" }) // SecurityManager and AccessController are deprecated
114- private static ConstantCallSite bootstrap (
108+ private static CallSite bootstrap (
115109 MethodHandles .Lookup lookup ,
116110 String adviceMethodName ,
117111 MethodType adviceMethodType ,
@@ -124,11 +118,11 @@ private static ConstantCallSite bootstrap(
124118 // callsite resolution needs privileged access to call Class#getClassLoader() and
125119 // MethodHandles$Lookup#findStatic
126120 return java .security .AccessController .doPrivileged (
127- (PrivilegedAction <ConstantCallSite >)
121+ (PrivilegedAction <CallSite >)
128122 () -> internalBootstrap (lookup , adviceMethodName , adviceMethodType , args ));
129123 }
130124
131- private static ConstantCallSite internalBootstrap (
125+ private static CallSite internalBootstrap (
132126 MethodHandles .Lookup lookup ,
133127 String adviceMethodName ,
134128 MethodType adviceMethodType ,
@@ -163,29 +157,39 @@ private static ConstantCallSite internalBootstrap(
163157 }
164158 }
165159
166- private static ConstantCallSite bootstrapAdvice (
160+ private static CallSite bootstrapAdvice (
167161 MethodHandles .Lookup lookup ,
168162 String adviceMethodName ,
169163 MethodType invokedynamicMethodType ,
170164 String moduleClassName ,
171165 String adviceMethodDescriptor ,
172166 String adviceClassName )
173167 throws NoSuchMethodException , IllegalAccessException , ClassNotFoundException {
174- CallDepth callDepth = CallDepth .forClass (IndyBootstrap .class );
175- try {
176- if (callDepth .getAndIncrement () > 0 ) {
168+ try (AdviceBootstrapState nestedState =
169+ AdviceBootstrapState .enter (
170+ lookup .lookupClass (),
171+ moduleClassName ,
172+ adviceClassName ,
173+ adviceMethodName ,
174+ adviceMethodDescriptor )) {
175+ if (nestedState .isNestedInvocation ()) {
177176 // avoid re-entrancy and stack overflow errors, which may happen when bootstrapping an
178177 // instrumentation that also gets triggered during the bootstrap
179178 // for example, adding correlation ids to the thread context when executing logger.debug.
180179 logger .log (
181- Level .SEVERE ,
182- "Nested instrumented invokedynamic instruction linkage detected for instrumented class {0} and advice {1}.{2}, the instrumentation might not work correctly " ,
180+ Level .FINE ,
181+ "Nested instrumented invokedynamic instruction linkage detected for instrumented class {0} and advice {1}.{2}, this invocation won't be instrumented " ,
183182 new Object [] {lookup .lookupClass ().getName (), adviceClassName , adviceMethodName });
184- logger .log (
185- Level .SEVERE ,
186- "Stacktrace for nested invokedynamic instruction linkage:" ,
187- new Throwable ());
188- return null ;
183+ if (logger .isLoggable (Level .FINEST )) {
184+ logger .log (
185+ Level .FINEST ,
186+ "Stacktrace for nested invokedynamic instruction linkage:" ,
187+ new Throwable ());
188+ }
189+ return nestedState .getOrInitMutableCallSite (
190+ () ->
191+ new MutableCallSite (
192+ IndyBootstrapDispatcher .generateNoopMethodHandle (invokedynamicMethodType )));
189193 }
190194
191195 InstrumentationModuleClassLoader instrumentationClassloader =
@@ -203,9 +207,17 @@ private static ConstantCallSite bootstrapAdvice(
203207 .getLookup ()
204208 .findStatic (adviceClass , adviceMethodName , actualAdviceMethodType )
205209 .asType (invokedynamicMethodType );
206- return new ConstantCallSite (methodHandle );
207- } finally {
208- callDepth .decrementAndGet ();
210+
211+ MutableCallSite nestedBootstrapCallSite = nestedState .getMutableCallSite ();
212+ if (nestedBootstrapCallSite != null ) {
213+ // There have been nested bootstrapping attempts
214+ // Update the callsite of those to run the actual instrumentation
215+ nestedBootstrapCallSite .setTarget (methodHandle );
216+ MutableCallSite .syncAll (new MutableCallSite [] {nestedBootstrapCallSite });
217+ return nestedBootstrapCallSite ;
218+ } else {
219+ return new ConstantCallSite (methodHandle );
220+ }
209221 }
210222 }
211223
0 commit comments