Skip to content

Commit 5f3f166

Browse files
committed
Fix problems with lambdas on recursive path
1 parent 0154cd3 commit 5f3f166

File tree

4 files changed

+61
-24
lines changed

4 files changed

+61
-24
lines changed

instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/DefineClassInstrumentation.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,17 @@ public static DefineClassContext onEnter(
5252
classLoader, className, classBytes, offset, length);
5353
}
5454

55+
// TODO: the ToReturned does nothing except for signaling the AdviceTransformer that it must
56+
// not touch this advice
57+
// this is done to ensure that ClassLoaderInstrumentationModule.loadAdviceClassesEagerly works
58+
// correctly
59+
// we can therefore remove it, as soon as the AdviceTransformer is not applied anymore
5560
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
56-
public static void onExit(
61+
@Advice.AssignReturned.ToReturned
62+
public static Class<?> onExit(
5763
@Advice.Enter DefineClassContext context, @Advice.Return Class<?> returned) {
5864
DefineClassHelper.afterDefineClass(context);
65+
return returned;
5966
}
6067
}
6168

@@ -69,10 +76,17 @@ public static DefineClassContext onEnter(
6976
return DefineClassHelper.beforeDefineClass(classLoader, className, classBytes);
7077
}
7178

79+
// TODO: the ToReturned does nothing except for signaling the AdviceTransformer that it must
80+
// not touch this advice
81+
// this is done to ensure that ClassLoaderInstrumentationModule.loadAdviceClassesEagerly works
82+
// correctly
83+
// we can therefore remove it, as soon as the AdviceTransformer is not applied anymore
7284
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
73-
public static void onExit(
85+
@Advice.AssignReturned.ToReturned
86+
public static Class<?> onExit(
7487
@Advice.Enter DefineClassContext context, @Advice.Return Class<?> returned) {
7588
DefineClassHelper.afterDefineClass(context);
89+
return returned;
7690
}
7791
}
7892
}

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceBootstrapState.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.lang.invoke.MutableCallSite;
99
import java.util.HashMap;
1010
import java.util.Map;
11+
import java.util.function.Function;
1112
import java.util.function.Supplier;
1213
import javax.annotation.Nullable;
1314

@@ -20,13 +21,31 @@ class AdviceBootstrapState implements AutoCloseable {
2021
private int recursionDepth;
2122
@Nullable private MutableCallSite nestedCallSite;
2223

24+
/**
25+
* We have to eagerly initialize to not cause a lambda construction
26+
* during {@link #enter(Class, String, String, String, String)}.
27+
*/
28+
private static final Function<Key, AdviceBootstrapState> CONSTRUCTOR = AdviceBootstrapState::new;
29+
2330
private AdviceBootstrapState(Key key) {
2431
this.key = key;
2532
// enter will increment it by one, so 0 is the value for non-recursive calls
2633
recursionDepth = -1;
2734
}
2835

29-
public static AdviceBootstrapState enter(
36+
static void initialize() {
37+
// Eager initialize everything because we could run into recursions doing this during advice
38+
// bootstrapping
39+
stateForCurrentThread.get();
40+
stateForCurrentThread.remove();
41+
try {
42+
Class.forName(Key.class.getName());
43+
} catch (ClassNotFoundException e) {
44+
throw new IllegalStateException(e);
45+
}
46+
}
47+
48+
static AdviceBootstrapState enter(
3049
Class<?> instrumentedClass,
3150
String moduleClassName,
3251
String adviceClassName,
@@ -39,8 +58,7 @@ public static AdviceBootstrapState enter(
3958
adviceClassName,
4059
adviceMethodName,
4160
adviceMethodDescriptor);
42-
AdviceBootstrapState state =
43-
stateForCurrentThread.get().computeIfAbsent(key, k -> new AdviceBootstrapState(key));
61+
AdviceBootstrapState state = stateForCurrentThread.get().computeIfAbsent(key, CONSTRUCTOR);
4462
state.recursionDepth++;
4563
return state;
4664
}
@@ -56,6 +74,13 @@ public MutableCallSite getOrInitMutableCallSite(Supplier<MutableCallSite> initia
5674
return nestedCallSite;
5775
}
5876

77+
public void initMutableCallSite(MutableCallSite mutableCallSite) {
78+
if (nestedCallSite != null) {
79+
throw new IllegalStateException("callsite has already been initialized");
80+
}
81+
nestedCallSite = mutableCallSite;
82+
}
83+
5984
@Nullable
6085
public MutableCallSite getMutableCallSite() {
6186
return nestedCallSite;
@@ -99,8 +124,12 @@ private Key(
99124

100125
@Override
101126
public boolean equals(Object o) {
102-
if (this == o) return true;
103-
if (o == null || getClass() != o.getClass()) return false;
127+
if (this == o) {
128+
return true;
129+
}
130+
if (o == null || !(o instanceof Key)) {
131+
return false;
132+
}
104133

105134
Key that = (Key) o;
106135
return instrumentedClass.equals(that.instrumentedClass)

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/IndyBootstrap.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ public class IndyBootstrap {
9292

9393
IndyBootstrapDispatcher.init(
9494
MethodHandles.lookup().findStatic(IndyBootstrap.class, "bootstrap", bootstrapMethodType));
95+
96+
AdviceBootstrapState.initialize();
9597
} catch (Exception e) {
9698
throw new IllegalStateException(e);
9799
}
@@ -176,20 +178,12 @@ private static CallSite bootstrapAdvice(
176178
// avoid re-entrancy and stack overflow errors, which may happen when bootstrapping an
177179
// instrumentation that also gets triggered during the bootstrap
178180
// for example, adding correlation ids to the thread context when executing logger.debug.
179-
logger.log(
180-
Level.FINE,
181-
"Nested instrumented invokedynamic instruction linkage detected for instrumented class {0} and advice {1}.{2}, this invocation won't be instrumented",
182-
new Object[] {lookup.lookupClass().getName(), adviceClassName, adviceMethodName});
183-
if (logger.isLoggable(Level.FINEST)) {
184-
logger.log(
185-
Level.FINEST,
186-
"Stacktrace for nested invokedynamic instruction linkage:",
187-
new Throwable());
181+
MutableCallSite mutableCallSite = nestedState.getMutableCallSite();
182+
if (mutableCallSite == null) {
183+
mutableCallSite = new MutableCallSite(IndyBootstrapDispatcher.generateNoopMethodHandle(invokedynamicMethodType));
184+
nestedState.initMutableCallSite(mutableCallSite);
188185
}
189-
return nestedState.getOrInitMutableCallSite(
190-
() ->
191-
new MutableCallSite(
192-
IndyBootstrapDispatcher.generateNoopMethodHandle(invokedynamicMethodType)));
186+
return mutableCallSite;
193187
}
194188

195189
InstrumentationModuleClassLoader instrumentationClassloader =
@@ -212,6 +206,10 @@ private static CallSite bootstrapAdvice(
212206
if (nestedBootstrapCallSite != null) {
213207
// There have been nested bootstrapping attempts
214208
// Update the callsite of those to run the actual instrumentation
209+
logger.log(
210+
Level.FINE,
211+
"Fixing nested instrumentation invokedynamic instruction bootstrapping for instrumented class {0} and advice {1}.{2}, the instrumentaiton should be active now",
212+
new Object[] {lookup.lookupClass().getName(), adviceClassName, adviceMethodName});
215213
nestedBootstrapCallSite.setTarget(methodHandle);
216214
MutableCallSite.syncAll(new MutableCallSite[] {nestedBootstrapCallSite});
217215
return nestedBootstrapCallSite;

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/InstrumentationModuleClassLoader.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import java.util.Map;
2626
import java.util.Set;
2727
import java.util.concurrent.ConcurrentHashMap;
28-
import java.util.logging.Logger;
2928
import java.util.stream.Collectors;
3029
import javax.annotation.Nullable;
3130
import net.bytebuddy.agent.builder.AgentBuilder;
@@ -53,9 +52,6 @@
5352
*/
5453
public class InstrumentationModuleClassLoader extends ClassLoader {
5554

56-
private static final Logger logger =
57-
Logger.getLogger(InstrumentationModuleClassLoader.class.getName());
58-
5955
static {
6056
ClassLoader.registerAsParallelCapable();
6157
}

0 commit comments

Comments
 (0)