Skip to content

Commit 3267e4c

Browse files
committed
Make helper-name resolution lazy
1 parent 48b4584 commit 3267e4c

2 files changed

Lines changed: 57 additions & 15 deletions

File tree

dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/CombiningTransformerBuilder.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.List;
2727
import java.util.Map;
2828
import java.util.Set;
29+
import java.util.function.Supplier;
2930
import net.bytebuddy.agent.builder.AgentBuilder;
3031
import net.bytebuddy.asm.Advice;
3132
import net.bytebuddy.asm.AsmVisitorWrapper;
@@ -130,18 +131,20 @@ private void prepareInstrumentation(InstrumenterModule module, int instrumentati
130131

131132
adviceShader = AdviceShader.with(module);
132133

133-
String[] helperClassNames = module.getAllHelperClassNames();
134-
if (module.injectHelperDependencies()) {
135-
helperClassNames = HelperScanner.withClassDependencies(helperClassNames);
136-
}
134+
// Resolve helper names lazily, so agent install doesn't load every module's generated $Muzzle
135+
// class.
137136
helperTransformer =
138-
helperClassNames.length > 0
139-
? new HelperTransformer(
140-
module.useAgentCodeSource(),
141-
adviceShader,
142-
module.getClass().getSimpleName(),
143-
helperClassNames)
144-
: null;
137+
new HelperTransformer(
138+
module.useAgentCodeSource(),
139+
adviceShader,
140+
module.getClass().getSimpleName(),
141+
() -> {
142+
String[] helperClassNames = module.getAllHelperClassNames();
143+
if (module.injectHelperDependencies()) {
144+
helperClassNames = HelperScanner.withClassDependencies(helperClassNames);
145+
}
146+
return helperClassNames;
147+
});
145148

146149
postProcessor = module.postProcessor();
147150

@@ -385,7 +388,7 @@ static final class HelperTransformer extends HelperInjector implements AgentBuil
385388
boolean useAgentCodeSource,
386389
AdviceShader adviceShader,
387390
String requestingName,
388-
String... helperClassNames) {
391+
Supplier<String[]> helperClassNames) {
389392
super(useAgentCodeSource, adviceShader, requestingName, helperClassNames);
390393
}
391394
}

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Set;
2222
import java.util.WeakHashMap;
2323
import java.util.concurrent.CopyOnWriteArrayList;
24+
import java.util.function.Supplier;
2425
import net.bytebuddy.description.type.TypeDescription;
2526
import net.bytebuddy.dynamic.ClassFileLocator;
2627
import net.bytebuddy.dynamic.DynamicType;
@@ -42,7 +43,10 @@ public class HelperInjector implements Instrumenter.TransformingAdvice {
4243
private final AdviceShader adviceShader;
4344
private final String requestingName;
4445

45-
private final Set<String> helperClassNames;
46+
// Helper names are resolved lazily: when a supplier is provided, resolution is deferred to the
47+
// first transform() so that we don't load the generated $Muzzle class at agent install.
48+
private final Supplier<String[]> helperClassNamesSupplier;
49+
private volatile Set<String> helperClassNames;
4650
private final Map<String, byte[]> dynamicTypeMap = new LinkedHashMap<>();
4751

4852
private final Map<ClassLoader, Boolean> injectedClassLoaders =
@@ -77,9 +81,27 @@ public HelperInjector(
7781
this.requestingName = requestingName;
7882
this.adviceShader = adviceShader;
7983

84+
this.helperClassNamesSupplier = null;
8085
this.helperClassNames = new LinkedHashSet<>(asList(helperClassNames));
8186
}
8287

88+
/**
89+
* Construct HelperInjector whose helper names are resolved lazily on first {@link #transform}, to
90+
* avoid resolving them (which may load the generated {@code $Muzzle} class) at agent install.
91+
*/
92+
public HelperInjector(
93+
final boolean useAgentCodeSource,
94+
final AdviceShader adviceShader,
95+
final String requestingName,
96+
final Supplier<String[]> helperClassNamesSupplier) {
97+
this.useAgentCodeSource = useAgentCodeSource;
98+
this.requestingName = requestingName;
99+
this.adviceShader = adviceShader;
100+
101+
this.helperClassNamesSupplier = helperClassNamesSupplier;
102+
this.helperClassNames = null;
103+
}
104+
83105
public HelperInjector(
84106
final boolean useAgentCodeSource,
85107
final String requestingName,
@@ -88,11 +110,27 @@ public HelperInjector(
88110
this.requestingName = requestingName;
89111
this.adviceShader = null;
90112

113+
this.helperClassNamesSupplier = null;
91114
helperClassNames = helperMap.keySet();
92115
dynamicTypeMap.putAll(helperMap);
93116
}
94117

95-
private Map<String, byte[]> getHelperMap() throws IOException {
118+
/** Resolves helper class names, deferring to the supplier when one's provided. */
119+
private Set<String> resolveHelperClassNames() {
120+
Set<String> names = helperClassNames;
121+
if (names == null) {
122+
synchronized (this) {
123+
names = helperClassNames;
124+
if (names == null) {
125+
names = new LinkedHashSet<>(asList(helperClassNamesSupplier.get()));
126+
helperClassNames = names;
127+
}
128+
}
129+
}
130+
return names;
131+
}
132+
133+
private Map<String, byte[]> getHelperMap(final Set<String> helperClassNames) throws IOException {
96134
if (dynamicTypeMap.isEmpty()) {
97135
final Map<String, byte[]> classnameToBytes = new LinkedHashMap<>();
98136
for (String helperName : helperClassNames) {
@@ -117,6 +155,7 @@ public DynamicType.Builder<?> transform(
117155
ClassLoader classLoader,
118156
final JavaModule module,
119157
final ProtectionDomain pd) {
158+
final Set<String> helperClassNames = resolveHelperClassNames();
120159
if (!helperClassNames.isEmpty()) {
121160
if (classLoader == null) {
122161
throw new UnsupportedOperationException(
@@ -135,7 +174,7 @@ public DynamicType.Builder<?> transform(
135174
String.join(",", helperClassNames));
136175
}
137176

138-
final Map<String, byte[]> classnameToBytes = getHelperMap();
177+
final Map<String, byte[]> classnameToBytes = getHelperMap(helperClassNames);
139178
final Collection<Class<?>> classes = injectClassLoader(classLoader, classnameToBytes);
140179

141180
// all datadog helper classes are in the unnamed module

0 commit comments

Comments
 (0)